[Particle, VFX] Improve curve evaluation performance.

This commit is contained in:
MakhamDev 2023-10-02 09:53:30 +07:00
parent f7c119a77b
commit 9380d2d77c
10 changed files with 337 additions and 187 deletions

Binary file not shown.

View file

@ -24,10 +24,23 @@ function __part(_node) constructor {
turning = 0;
turnSpd = 0;
drawx = 0;
drawy = 0;
drawrot = 0;
drawsx = 0;
drawsy = 0;
accel = 0;
spVec = [ 0, 0 ];
wig_pos = 0;
//wig_psx = new wiggleMap(seed, 1, PROJECT.animator.frames_total);
//wig_psy = new wiggleMap(seed, 1, PROJECT.animator.frames_total);
//wig_scx = new wiggleMap(seed, 1, PROJECT.animator.frames_total);
//wig_scy = new wiggleMap(seed, 1, PROJECT.animator.frames_total);
//wig_rot = new wiggleMap(seed, 1, PROJECT.animator.frames_total);
//wig_dir = new wiggleMap(seed, 1, PROJECT.animator.frames_total);
boundary_data = -1;
@ -64,7 +77,7 @@ function __part(_node) constructor {
ground_bounce = 0;
ground_friction = 1;
static create = function(_surf, _x, _y, _life) {
static create = function(_surf, _x, _y, _life) { #region
active = true;
surf = _surf;
x = _x;
@ -76,9 +89,9 @@ function __part(_node) constructor {
life = _life;
life_total = life;
node.onPartCreate(self);
}
} #endregion
static setPhysic = function(_sx, _sy, _ac, _g, _gDir, _wig_pos, _turn, _turnSpd) {
static setPhysic = function(_sx, _sy, _ac, _g, _gDir, _turn, _turnSpd) { #region
speedx = _sx;
speedy = _sy;
accel = _ac;
@ -90,20 +103,34 @@ function __part(_node) constructor {
turning = _turn;
turnSpd = _turnSpd;
wig_pos = _wig_pos;
spVec[0] = point_distance(0, 0, speedx, speedy);
spVec[1] = point_direction(0, 0, speedx, speedy);
}
} #endregion
static setGround = function(_ground, _ground_offset, _ground_bounce, _ground_frict) {
static setWiggle = function(wiggle_maps) { #region
//wig_psx.check(_wig_pos[0], _wig_pos[1], seed + 10);
//wig_psy.check(_wig_pos[0], _wig_pos[1], seed + 20);
//wig_rot.check(_wig_rot[0], _wig_rot[1], seed + 30);
//wig_scx.check(_wig_sca[0], _wig_sca[1], seed + 40);
//wig_scy.check(_wig_sca[0], _wig_sca[1], seed + 50);
//wig_dir.check(_wig_dir[0], _wig_dir[1], seed + 60);
wig_psx = wiggle_maps.wig_psx;
wig_psy = wiggle_maps.wig_psy;
wig_rot = wiggle_maps.wig_rot;
wig_scx = wiggle_maps.wig_scx;
wig_scy = wiggle_maps.wig_scy;
wig_dir = wiggle_maps.wig_dir;
} #endregion
static setGround = function(_ground, _ground_offset, _ground_bounce, _ground_frict) { #region
ground = _ground;
ground_y = y + _ground_offset;
ground_bounce = _ground_bounce;
ground_friction = clamp(1 - _ground_frict, 0, 1);
}
} #endregion
static setTransform = function(_scx, _scy, _sct, _rot, _rots, _follow) {
static setTransform = function(_scx, _scy, _sct, _rot, _rots, _follow) { #region
sc_sx = _scx;
sc_sy = _scy;
sct = _sct;
@ -111,23 +138,23 @@ function __part(_node) constructor {
rot = _rot;
rot_s = _rots;
follow = _follow;
}
} #endregion
static setDraw = function(_col, _blend, _alp, _fade) {
static setDraw = function(_col, _blend, _alp, _fade) { #region
col = _col;
blend = _blend;
alp = _alp;
alp_draw = _alp;
alp_fade = _fade;
}
} #endregion
static kill = function() {
static kill = function() { #region
active = false;
node.onPartDestroy(self);
}
} #endregion
static step = function() {
static step = function() { #region
if(!active) return;
x += speedx;
@ -145,10 +172,9 @@ function __part(_node) constructor {
var dirr = point_direction(0, 0, speedx, speedy);
var diss = point_distance(0, 0, speedx, speedy);
diss = max(0, diss + accel);
if(speedx != 0 || speedy != 0) {
if(wig_pos != 0)
dirr += random_range(-wig_pos, wig_pos);
dirr += wig_dir.get(seed + life);
if(turning != 0) {
var trn = turnSpd? turning * diss : turning;
@ -173,9 +199,21 @@ function __part(_node) constructor {
prevx = x;
prevy = y;
}
drawx = x;
drawy = y;
drawrot = rot;
drawsx = sc_sx;
drawsy = sc_sy;
drawx += wig_psx.get(seed + life);
drawy += wig_psy.get(seed + life);
drawrot += wig_rot.get(seed + life);
drawsx += wig_scy.get(seed + life);
drawsy += wig_scy.get(seed + life);
} #endregion
static draw = function(exact, surf_w, surf_h) {
static draw = function(exact, surf_w, surf_h) { #region
var ss = surf;
if(is_array(surf)) {
var ind = abs(round((life_total - life) * anim_speed));
@ -201,9 +239,9 @@ function __part(_node) constructor {
if(!is_surface(surface)) return;
var lifeRat = 1 - life / life_total;
var scCurve = eval_curve_x(sct, lifeRat);
scx = sc_sx * scCurve;
scy = sc_sy * scCurve;
var scCurve = sct.get(lifeRat);
scx = drawsx * scCurve;
scy = drawsy * scCurve;
var _xx, _yy;
var s_w = surface_get_width_safe(surface) * scx;
@ -211,8 +249,8 @@ function __part(_node) constructor {
if(boundary_data == -1) {
var _pp = point_rotate(-s_w / 2, -s_h / 2, 0, 0, rot);
_xx = x + _pp[0];
_yy = y + _pp[1];
_xx = drawx + _pp[0];
_yy = drawy + _pp[1];
} else {
var ww = boundary_data[2] + boundary_data[0];
var hh = boundary_data[3] + boundary_data[1];
@ -222,8 +260,8 @@ function __part(_node) constructor {
var _pp = point_rotate(-cx, -cy, 0, 0, rot);
_xx = x + cx + _pp[0] * scx;
_yy = y + cy + _pp[1] * scy;
_xx = drawx + cx + _pp[0] * scx;
_yy = drawy + cy + _pp[1] * scy;
}
if(exact) {
@ -240,12 +278,12 @@ function __part(_node) constructor {
var cc = (col == -1)? c_white : col.eval(lifeRat);
if(blend != c_white) cc = colorMultiply(blend, cc);
alp_draw = alp * eval_curve_x(alp_fade, lifeRat);
alp_draw = alp * alp_fade.get(lifeRat);
draw_surface_ext_safe(surface, _xx, _yy, scx, scy, rot, cc, alp_draw);
}
draw_surface_ext_safe(surface, _xx, _yy, scx, scy, drawrot, cc, alp_draw);
} #endregion
static getPivot = function() {
static getPivot = function() { #region
if(boundary_data == -1)
return [x, y];
@ -255,7 +293,7 @@ function __part(_node) constructor {
var cy = y + boundary_data[1] + hh / 2;
return [cx, cy];
}
} #endregion
}
#region helper

View file

@ -60,8 +60,8 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co
.setDisplay(VALUE_DISPLAY.range, { linked : true })
.rejectArray();
inputs[| 20] = nodeValue("Wiggle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ] )
.setDisplay(VALUE_DISPLAY.range, { linked : true })
inputs[| 20] = nodeValue("Direction wiggle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ] )
.setDisplay(VALUE_DISPLAY.vector, { label: [ "Amplitude", "Period" ], linkable: false, per_line: true })
.rejectArray();
inputs[| 21] = nodeValue("Loop", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, true )
@ -132,16 +132,29 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co
.rejectArray()
.setDisplay(VALUE_DISPLAY.slider, [ 0, 1, 0.01 ]);
inputs[| 41] = nodeValue("Position wiggle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ] )
.setDisplay(VALUE_DISPLAY.vector, { label: [ "Amplitude", "Period" ], linkable: false, per_line: true })
.rejectArray();
inputs[| 42] = nodeValue("Rotation wiggle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ] )
.setDisplay(VALUE_DISPLAY.vector, { label: [ "Amplitude", "Period" ], linkable: false, per_line: true })
.rejectArray();
inputs[| 43] = nodeValue("Scale wiggle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0 ] )
.setDisplay(VALUE_DISPLAY.vector, { label: [ "Amplitude", "Period" ], linkable: false, per_line: true })
.rejectArray();
input_len = ds_list_size(inputs);
input_display_list = [ 32,
["Sprite", false], 0, 22, 23, 26,
["Spawn", true], 27, 16, 1, 2, 3, 4, 30, 31, 24, 25, 5,
["Movement", true], 29, 6, 18,
["Physics", true], 7, 19, 33, 20, 34, 35, 36,
["Physics", true], 7, 19, 33, 34, 35, 36,
["Ground", true], 37, 38, 39, 40,
["Rotation", true], 15, 8, 9,
["Scale", true], 10, 17, 11,
["Wiggles", true], 20, 41, 42, 43,
["Color", true], 12, 28, 13, 14,
["Render", true], 21
];
@ -161,7 +174,19 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co
current_data = [];
surface_cache = {};
for(var i = 0; i < attributes.part_amount; i++)
wiggle_maps = {
wig_psx: new wiggleMap(seed, 1, 1000),
wig_psy: new wiggleMap(seed, 1, 1000),
wig_scx: new wiggleMap(seed, 1, 1000),
wig_scy: new wiggleMap(seed, 1, 1000),
wig_rot: new wiggleMap(seed, 1, 1000),
wig_dir: new wiggleMap(seed, 1, 1000),
};
curve_scale = noone;
curve_alpha = noone;
for( var i = 0; i < attributes.part_amount; i++ )
parts[i] = new __part(self);
static spawn = function(_time = PROJECT.animator.current_frame, _pos = -1) { #region
@ -184,7 +209,6 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co
var _accel = current_data[ 7];
var _grav = current_data[19];
var _gvDir = current_data[33];
var _wigg = current_data[20];
var _turn = current_data[34];
var _turnBi = current_data[35];
var _turnSc = current_data[36];
@ -194,12 +218,10 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co
var _rotation_speed = current_data[ 9];
var _scale = current_data[10];
var _size = current_data[17];
var _scale_time = current_data[11];
var _color = current_data[12];
var _blend = current_data[28];
var _alpha = current_data[13];
var _fade = current_data[14];
var _arr_type = current_data[22];
var _anim_speed = current_data[23];
@ -304,12 +326,12 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co
if(_turnBi) _trn *= choose(-1, 1);
var _gravity = random_range(_grav[0], _grav[1]);
var _wiggle = random_range(_wigg[0], _wigg[1]);
part.setPhysic(_vx, _vy, _acc, _gravity, _gvDir, _wiggle, _trn, _turnSc);
part.setPhysic(_vx, _vy, _acc, _gravity, _gvDir, _trn, _turnSc);
part.setWiggle(wiggle_maps);
part.setGround(_ground, _ground_offset, _ground_bounce, _ground_frict);
part.setTransform(_scx, _scy, _scale_time, _rot, _rot_spd, _follow);
part.setDraw(_color, _bld, _alp, _fade);
part.setTransform(_scx, _scy, curve_scale, _rot, _rot_spd, _follow);
part.setDraw(_color, _bld, _alp, curve_alpha);
spawn_index = safe_mod(spawn_index + 1, attributes.part_amount);
onSpawn(_time, part);
@ -332,6 +354,24 @@ function Node_VFX_Spawner_Base(_x, _y, _group = noone) : Node(_x, _y, _group) co
render();
seed = inputs[| 32].getValue();
var _wigg_pos = inputs[| 41].getValue();
var _wigg_rot = inputs[| 42].getValue();
var _wigg_sca = inputs[| 43].getValue();
var _wigg_dir = inputs[| 20].getValue();
wiggle_maps.wig_psx.check(_wigg_pos[0], _wigg_pos[1], seed + 10);
wiggle_maps.wig_psy.check(_wigg_pos[0], _wigg_pos[1], seed + 20);
wiggle_maps.wig_rot.check(_wigg_rot[0], _wigg_rot[1], seed + 30);
wiggle_maps.wig_scx.check(_wigg_sca[0], _wigg_sca[1], seed + 40);
wiggle_maps.wig_scy.check(_wigg_sca[0], _wigg_sca[1], seed + 50);
wiggle_maps.wig_dir.check(_wigg_dir[0], _wigg_dir[1], seed + 60);
var _curve_sca = inputs[| 11].getValue();
var _curve_alp = inputs[| 14].getValue();
curve_scale = new curveMap(_curve_sca, PROJECT.animator.frames_total);
curve_alpha = new curveMap(_curve_alp, PROJECT.animator.frames_total);
var keys = variable_struct_get_names(surface_cache);
for( var i = 0, n = array_length(keys); i < n; i++ )
surface_free_safe(surface_cache[$ keys[i]]);

View file

@ -4,7 +4,7 @@
#macro CURVE_DEF_10 [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]
function draw_curve(x0, y0, _w, _h, _bz, miny = 0, maxy = 1) {
function draw_curve(x0, y0, _w, _h, _bz, miny = 0, maxy = 1) { #region
var segments = array_length(_bz) / 6 - 1;
for( var i = 0; i < segments; i++ ) {
@ -30,9 +30,9 @@ function draw_curve(x0, y0, _w, _h, _bz, miny = 0, maxy = 1) {
draw_curve_segment(dx0, y0, dw, _h, [_y0, ax0, ay0, bx1, by1, _y1], smp, miny, maxy);
}
}
} #endregion
function draw_curve_segment(x0, y0, _w, _h, _bz, SAMPLE = 32, miny = 0, maxy = 1) {
function draw_curve_segment(x0, y0, _w, _h, _bz, SAMPLE = 32, miny = 0, maxy = 1) { #region
var _ox, _oy;
for(var i = 0; i <= SAMPLE; i++) {
@ -50,9 +50,9 @@ function draw_curve_segment(x0, y0, _w, _h, _bz, SAMPLE = 32, miny = 0, maxy = 1
_ox = _nx;
_oy = _ny;
}
}
} #endregion
function eval_curve_segment_t_position(t, _bz) {
function eval_curve_segment_t_position(t, _bz) { #region
return [
power(1 - t, 3) * 0
+ 3 * power(1 - t, 2) * t * _bz[1]
@ -64,16 +64,16 @@ function eval_curve_segment_t_position(t, _bz) {
+ 3 * (1 - t) * power(t, 2) * _bz[4]
+ power(t, 3) * _bz[5]
];
}
} #endregion
function eval_curve_segment_t(_bz, t) {
function eval_curve_segment_t(_bz, t) { #region
return power(1 - t, 3) * _bz[0]
+ 3 * power(1 - t, 2) * t * _bz[2]
+ 3 * (1 - t) * power(t, 2) * _bz[4]
+ power(t, 3) * _bz[5];
}
} #endregion
function eval_curve_x(_bz, _x, _prec = 0.00001) {
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_10 = [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];
@ -104,13 +104,13 @@ function eval_curve_x(_bz, _x, _prec = 0.00001) {
if(_x < _x0) continue;
if(_x > _x1) continue;
return eval_curve_segment_x([_y0, ax0, ay0, bx1, by1, _y1], (_x - _x0) / (_x1 - _x0));
return eval_curve_segment_x([_y0, ax0, ay0, bx1, by1, _y1], (_x - _x0) / (_x1 - _x0), _tolr);
}
return array_safe_get(_bz, array_length(_bz) - 3);
}
} #endregion
function eval_curve_segment_x(_bz, _x, _prec = 0.00001) {
function eval_curve_segment_x(_bz, _x, _tolr = 0.00001) { #region
var st = 0;
var ed = 1;
@ -127,7 +127,7 @@ function eval_curve_segment_x(_bz, _x, _prec = 0.00001) {
+ 3 * (1 - _xt) * power(_xt, 2) * _bz[3]
+ power(_xt, 3) * 1;
if(abs(_ftx - _x) < _prec)
if(abs(_ftx - _x) < _tolr)
return eval_curve_segment_t(_bz, _xt);
if(_xt < _x)
@ -152,24 +152,39 @@ function eval_curve_segment_x(_bz, _x, _prec = 0.00001) {
_xt -= _ftx / slope;
if(abs(_ftx) < _prec)
if(abs(_ftx) < _tolr)
break;
}
_xt = clamp(_xt, 0, 1);
return eval_curve_segment_t(_bz, _xt);
}
} #endregion
function bezier_range(bz) {
return [ min(bz[0], bz[2], bz[4], bz[5]), max(bz[0], bz[2], bz[4], bz[5]) ];
}
function bezier_range(bz) { return [ min(bz[0], bz[2], bz[4], bz[5]), max(bz[0], bz[2], bz[4], bz[5]) ]; }
function ease_cubic_in(rat) {
return power(rat, 3);
}
function ease_cubic_out(rat) {
return 1 - power(1 - rat, 3);
}
function ease_cubic_inout(rat) {
return rat < 0.5 ? 4 * power(rat, 3) : 1 - power(-2 * rat + 2, 3) / 2;
function ease_cubic_in(rat) { return power(rat, 3); }
function ease_cubic_out(rat) { return 1 - power(1 - rat, 3); }
function ease_cubic_inout(rat) { return rat < 0.5 ? 4 * power(rat, 3) : 1 - power(-2 * rat + 2, 3) / 2; }
function curveMap(_bz, _prec = 32, _tolr = 0.00001) constructor {
bz = _bz;
prec = _prec;
size = 1 / _prec;
tolr = _tolr;
map = array_create(_prec);
for( var i = 0; i < _prec; i++ )
map[i] = eval_curve_x(bz, i * size, tolr);
static get = function(i) { #region
gml_pragma("forceinline");
var _ind = clamp(i, 0, 1) * (prec - 1);
var _indL = floor(_ind);
var _indH = ceil(_ind);
var _indF = frac(_ind);
if(_indL == _indH) return map[_ind];
return lerp(map[_indL], map[_indH], _indF);
} #endregion
}

View file

@ -73,6 +73,8 @@
function __txt_node_name(node, def = "") {
gml_pragma("forceinline");
if(TESTING) return def;
if(!struct_has(LOCALE.node, node))
return def;
@ -83,6 +85,8 @@
function __txt_node_tooltip(node, def = "") {
gml_pragma("forceinline");
if(TESTING) return def;
if(!struct_has(LOCALE.node, node))
return def;
@ -93,6 +97,8 @@
function __txt_junction_name(node, type, index, def = "") {
gml_pragma("forceinline");
if(TESTING) return def;
if(!struct_has(LOCALE.node, node))
return def;
@ -107,6 +113,8 @@
function __txt_junction_tooltip(node, type, index, def = "") {
gml_pragma("forceinline");
if(TESTING) return def;
if(!struct_has(LOCALE.node, node))
return def;
@ -121,6 +129,8 @@
function __txt_junction_data(node, type, index, def = []) {
gml_pragma("forceinline");
if(TESTING) return def;
if(!struct_has(LOCALE.node, node))
return def;

View file

@ -69,7 +69,7 @@ function drawWidget(xx, yy, ww, _m, jun, global_var = true, _hover = false, _foc
if(visi_hold != noone && mouse_release(mb_left))
visi_hold = noone;
var cc = COLORS._main_text_inner;
var cc = COLORS._main_text;
if(jun.expUse) {
var expValid = jun.expTree != noone && jun.expTree.validate();
cc = expValid? COLORS._main_value_positive : COLORS._main_value_negative;

View file

@ -759,6 +759,10 @@ function NodeValue(_name, _node, _connect, _type, _value, _tooltip = "") constru
return setValueDirect(val, index);
}, unit );
if(struct_has(display_data, "label")) editWidget.axis = display_data.label;
if(struct_has(display_data, "linkable")) editWidget.linkable = display_data.linkable;
if(struct_has(display_data, "per_line")) editWidget.per_line = display_data.per_line;
if(type == VALUE_TYPE.integer) editWidget.setSlideSpeed(1);
extra_data = { linked : false, side_button : noone };

View file

@ -1,97 +1,4 @@
function irandom_seed(val, seed) {
random_set_seed(floor(seed));
return irandom(val);
}
function irandom_range_seed(from, to, seed) {
random_set_seed(floor(seed));
return irandom_range(from, to);
}
function random_seed(val, seed) {
random_set_seed(floor(seed));
var _s0 = random(val);
random_set_seed(floor(seed) + 1);
var _s1 = random(val);
return lerp(_s0, _s1, frac(seed));
}
function random_range_seed(from, to, seed) {
random_set_seed(floor(seed));
var _s0 = random_range(from, to);
random_set_seed(floor(seed) + 1);
var _s1 = random_range(from, to);
return lerp(_s0, _s1, frac(seed));
}
function random1D(seed, startRange = 0, endRange = 1) {
if(startRange == endRange) return startRange;
var _f = frac(seed);
if(_f == 0) {
random_set_seed(PROJECT.seed + seed);
return random_range(startRange, endRange);
}
random_set_seed(PROJECT.seed + floor(seed));
var f1 = random_range(startRange, endRange);
random_set_seed(PROJECT.seed + floor(seed) + 1);
var f2 = random_range(startRange, endRange);
return lerp(f1, f2, _f);
}
function perlin1D(seed, scale = 1, octave = 1, startRange = 0, endRange = 1) {
var amp = power(2., octave - 1.) / (power(2., octave) - 1.);
var val = 0;
repeat(octave) {
val = random1D(seed * scale) * amp;
scale *= 2;
amp /= 2;
}
return lerp(startRange, endRange, val);
}
function wiggle(_min = 0, _max = 1, _freq = 1, _time = 0, _seed = 0, _octave = 1) {
_freq = max(1, _freq);
var sdMin = floor(_time / _freq) * _freq;
var sdMax = sdMin + _freq;
var _x0 = perlin1D(PROJECT.seed + _seed + sdMin, 1, _octave);
var _x1 = perlin1D(PROJECT.seed + _seed + sdMax, 1, _octave);
var t = (_time - sdMin) / (sdMax - sdMin);
t = -(cos(pi * t) - 1) / 2;
var _lrp = lerp(_x0, _x1, t);
return lerp(_min, _max, _lrp);
}
function getWiggle(_min = 0, _max = 1, _freq = 1, _time = 0, _seed = 0, startTime = noone, endTime = noone) {
_freq = max(1, _freq);
var sdMin = floor(_time / _freq) * _freq;
var sdMax = sdMin + _freq;
if(endTime) //Clip at ending
sdMax = min(endTime, sdMax);
var _x0 = (startTime != noone && sdMin <= startTime)? 0.5 : random1D(PROJECT.seed + _seed + sdMin);
var _x1 = (endTime != noone && sdMax >= endTime)? 0.5 : random1D(PROJECT.seed + _seed + sdMax);
var t = (_time - sdMin) / (sdMax - sdMin);
t = -(cos(pi * t) - 1) / 2;
var _lrp = lerp(_x0, _x1, t);
return lerp(_min, _max, _lrp);
}
function UUID_generate(length = 32) {
function UUID_generate(length = 32) { #region
randomize();
static str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static month = "JFRAMJYASOND"
@ -107,4 +14,130 @@ function UUID_generate(length = 32) {
repeat(length - string_length(_id)) _id += string_char_at(str, irandom_range(1, string_length(str)));
return _id;
}
} #endregion
function irandom_seed(val, seed) { #region
random_set_seed(floor(seed));
return irandom(val);
} #endregion
function irandom_range_seed(from, to, seed) { #region
random_set_seed(floor(seed));
return irandom_range(from, to);
} #endregion
function random_seed(val, seed) { #region
random_set_seed(floor(seed));
var _s0 = random(val);
random_set_seed(floor(seed) + 1);
var _s1 = random(val);
return lerp(_s0, _s1, frac(seed));
} #endregion
function random_range_seed(from, to, seed) { #region
random_set_seed(floor(seed));
var _s0 = random_range(from, to);
random_set_seed(floor(seed) + 1);
var _s1 = random_range(from, to);
return lerp(_s0, _s1, frac(seed));
} #endregion
function random1D(seed, startRange = 0, endRange = 1) { #region
if(startRange == endRange) return startRange;
var _f = frac(seed);
if(_f == 0) {
random_set_seed(PROJECT.seed + seed);
return random_range(startRange, endRange);
}
random_set_seed(PROJECT.seed + floor(seed));
var f1 = random_range(startRange, endRange);
random_set_seed(PROJECT.seed + floor(seed) + 1);
var f2 = random_range(startRange, endRange);
return lerp(f1, f2, _f);
} #endregion
function perlin1D(seed, scale = 1, octave = 1, startRange = 0, endRange = 1) { #region
var amp = power(2., octave - 1.) / (power(2., octave) - 1.);
var val = 0;
repeat(octave) {
val = random1D(seed * scale) * amp;
scale *= 2;
amp /= 2;
}
return lerp(startRange, endRange, val);
} #endregion
function wiggle(_min = 0, _max = 1, _freq = 1, _time = 0, _seed = 0, _octave = 1) { #region
_freq = max(1, _freq);
var sdMin = floor(_time / _freq) * _freq;
var sdMax = sdMin + _freq;
var _x0 = perlin1D(PROJECT.seed + _seed + sdMin, 1, _octave);
var _x1 = perlin1D(PROJECT.seed + _seed + sdMax, 1, _octave);
var t = (_time - sdMin) / (sdMax - sdMin);
t = -(cos(pi * t) - 1) / 2;
var _lrp = lerp(_x0, _x1, t);
return lerp(_min, _max, _lrp);
} #endregion
function getWiggle(_min = 0, _max = 1, _freq = 1, _time = 0, _seed = 0, startTime = noone, endTime = noone) { #region
_freq = max(1, _freq);
var sdMin = floor(_time / _freq) * _freq;
var sdMax = sdMin + _freq;
if(endTime) //Clip at ending
sdMax = min(endTime, sdMax);
var _x0 = (startTime != noone && sdMin <= startTime)? 0.5 : random1D(PROJECT.seed + _seed + sdMin);
var _x1 = (endTime != noone && sdMax >= endTime)? 0.5 : random1D(PROJECT.seed + _seed + sdMax);
var t = (_time - sdMin) / (sdMax - sdMin);
t = -(cos(pi * t) - 1) / 2;
var _lrp = lerp(_x0, _x1, t);
return lerp(_min, _max, _lrp);
} #endregion
function wiggleMap(_seed, _freq, _length) constructor { #region
seed = _seed;
freq = _freq;
len = _length;
amp = 1;
map = array_create(_length);
static generate = function() {
gml_pragma("forceinline");
for(var i = 0; i < len; i++) map[i] = wiggle(-1, 1, freq, i, seed);
}
static check = function(_amp, _freq, _seed) {
gml_pragma("forceinline");
amp = _amp;
if(seed == _seed && freq == _freq) return;
//print($"Check {seed}:{_seed}, {freq}:{_freq} ({irandom(999999)})");
seed = _seed;
freq = _freq;
generate();
}
static get = function(i) {
gml_pragma("forceinline");
if(amp == 0) return 0;
return map[abs(i) % len] * amp;
}
} #endregion

View file

@ -154,8 +154,8 @@ function is_surface(s) {
if(!s) return false;
if(!surface_exists(s)) return false;
if(surface_get_width_safe(s) <= 0) return false;
if(surface_get_height_safe(s) <= 0) return false;
//if(surface_get_width_safe(s) <= 0) return false;
//if(surface_get_height_safe(s) <= 0) return false;
return true;
}

View file

@ -7,6 +7,9 @@ function vectorBox(_size, _onModify, _unit = noone) : widget() constructor {
size = _size;
onModify = _onModify;
unit = _unit;
linkable = true;
per_line = false;
current_value = [];
extra_data = { linked : false, side_button : noone };
@ -87,7 +90,7 @@ function vectorBox(_size, _onModify, _unit = noone) : widget() constructor {
x = _x;
y = _y;
w = _w;
h = _h;
h = per_line? (_h + ui(8)) * size - ui(8) : _h;
if(struct_has(_extra_data, "linked")) extra_data.linked = _extra_data.linked;
if(struct_has(_extra_data, "side_button")) extra_data.side_button = _extra_data.side_button;
@ -113,37 +116,44 @@ function vectorBox(_size, _onModify, _unit = noone) : widget() constructor {
_w -= ui(40);
}
var _icon_blend = extra_data.linked? COLORS._main_accent : (link_inactive_color == noone? COLORS._main_icon : link_inactive_color);
var bx = _x;
var by = _y + _h / 2 - ui(32 / 2);
if(buttonInstant(THEME.button_hide, bx + ui(4), by + ui(4), ui(24), ui(24), _m, active, hover, tooltip, THEME.value_link, extra_data.linked, _icon_blend) == 2) {
extra_data.linked = !extra_data.linked;
_extra_data.linked = extra_data.linked;
if(linkable) {
var _icon_blend = extra_data.linked? COLORS._main_accent : (link_inactive_color == noone? COLORS._main_icon : link_inactive_color);
var bx = _x;
var by = _y + _h / 2 - ui(32 / 2);
if(buttonInstant(THEME.button_hide, bx + ui(4), by + ui(4), ui(24), ui(24), _m, active, hover, tooltip, THEME.value_link, extra_data.linked, _icon_blend) == 2) {
extra_data.linked = !extra_data.linked;
_extra_data.linked = extra_data.linked;
if(extra_data.linked) {
onModify(0, _data[0]);
onModify(1, _data[0]);
if(extra_data.linked) {
onModify(0, _data[0]);
onModify(1, _data[0]);
}
}
_x += ui(28);
_w -= ui(28);
}
_x += ui(28);
_w -= ui(28);
var sz = min(size, array_length(_data));
var ww = _w / sz;
var ww = per_line? _w : _w / sz;
for(var i = 0; i < sz; i++) {
tb[i].setFocusHover(active, hover);
draw_set_font(f_p0);
var lw = max(ui(24), string_width(axis[i]) + ui(16));
var bx = _x + ww * i;
tb[i].draw(bx + ui(24), _y, ww - ui(24), _h, _data[i], _m);
var bx = per_line? _x : _x + ww * i;
var by = per_line? _y + (_h + ui(8)) * i : _y;
tb[i].setFocusHover(active, hover);
tb[i].draw(bx + lw, by, ww - lw, _h, _data[i], _m);
draw_set_text(f_p0, fa_left, fa_center, COLORS._main_text_inner);
draw_text(bx + ui(8), _y + _h / 2, axis[i]);
draw_text_add(bx + ui(8), by + _h / 2, axis[i]);
}
resetFocus();
return _h;
return h;
}
static apply = function() {