reaching ik

This commit is contained in:
Tanasart 2023-06-26 18:55:41 +02:00
parent 95384584ab
commit 4251afa2e4
16 changed files with 422 additions and 279 deletions

View file

@ -727,7 +727,7 @@
{"name":"node_perlin_smear","order":9,"path":"scripts/node_perlin_smear/node_perlin_smear.yy",},
{"name":"node_alpha_cutoff","order":10,"path":"scripts/node_alpha_cutoff/node_alpha_cutoff.yy",},
{"name":"sh_channel_R","order":4,"path":"shaders/sh_channel_R/sh_channel_R.yy",},
{"name":"draw_circle_border","order":3,"path":"scripts/draw_circle_border/draw_circle_border.yy",},
{"name":"draw_circle_functions","order":3,"path":"scripts/draw_circle_functions/draw_circle_functions.yy",},
{"name":"s_node_text_file_write","order":12,"path":"sprites/s_node_text_file_write/s_node_text_file_write.yy",},
{"name":"sliderRange","order":16,"path":"scripts/sliderRange/sliderRange.yy",},
{"name":"point_rect_overlap","order":2,"path":"scripts/point_rect_overlap/point_rect_overlap.yy",},
@ -973,7 +973,6 @@
{"name":"fd_rectangle_set_collision_mask_surface","order":2,"path":"scripts/fd_rectangle_set_collision_mask_surface/fd_rectangle_set_collision_mask_surface.yy",},
{"name":"node_array_length","order":11,"path":"scripts/node_array_length/node_array_length.yy",},
{"name":"node_erode","order":9,"path":"scripts/node_erode/node_erode.yy",},
{"name":"draw_circle_angle","order":15,"path":"scripts/draw_circle_angle/draw_circle_angle.yy",},
{"name":"node_wrap_mesh","order":6,"path":"scripts/node_wrap_mesh/node_wrap_mesh.yy",},
{"name":"sh_alpha_hash","order":43,"path":"shaders/sh_alpha_hash/sh_alpha_hash.yy",},
{"name":"panel_node_align","order":3,"path":"scripts/panel_node_align/panel_node_align.yy",},
@ -1125,7 +1124,6 @@
{"name":"draw_UI_scale","order":8,"path":"scripts/draw_UI_scale/draw_UI_scale.yy",},
{"name":"s_node_strandSim_update","order":1,"path":"sprites/s_node_strandSim_update/s_node_strandSim_update.yy",},
{"name":"s_node_RGB_combine","order":45,"path":"sprites/s_node_RGB_combine/s_node_RGB_combine.yy",},
{"name":"draw_circle_prec","order":23,"path":"scripts/draw_circle_prec/draw_circle_prec.yy",},
{"name":"s_node_shadow_cast","order":49,"path":"sprites/s_node_shadow_cast/s_node_shadow_cast.yy",},
{"name":"fft_functions","order":1,"path":"scripts/fft_functions/fft_functions.yy",},
{"name":"path_function","order":4,"path":"scripts/path_function/path_function.yy",},

View file

@ -448,6 +448,7 @@
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_anchor_scale.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/preview",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_anchor_solid.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/preview",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_anchor.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/preview",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_bone_IK.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/preview",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_cursor_path_add.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/preview",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_cursor_path_anchor.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/preview",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_cursor_path_move.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/preview",},
@ -464,6 +465,7 @@
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_3d_tool_transform.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/tool",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_bone_tool_add.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/tool",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_bone_tool_detach.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/tool",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_bone_tool_IK.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/tool",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_bone_tool_remove.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/tool",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_bone_tool_transform.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/tool",},
{"resourceType":"GMIncludedFile","resourceVersion":"1.0","name":"s_canvas_channel.png","CopyToMask":-1,"filePath":"datafiles/data/themes/default/graphics/tool",},
@ -1272,7 +1274,7 @@
{"id":{"name":"node_alpha_cutoff","path":"scripts/node_alpha_cutoff/node_alpha_cutoff.yy",},},
{"id":{"name":"pack_best_fit","path":"scripts/pack_best_fit/pack_best_fit.yy",},},
{"id":{"name":"sh_channel_R","path":"shaders/sh_channel_R/sh_channel_R.yy",},},
{"id":{"name":"draw_circle_border","path":"scripts/draw_circle_border/draw_circle_border.yy",},},
{"id":{"name":"draw_circle_functions","path":"scripts/draw_circle_functions/draw_circle_functions.yy",},},
{"id":{"name":"s_node_text_file_write","path":"sprites/s_node_text_file_write/s_node_text_file_write.yy",},},
{"id":{"name":"sliderRange","path":"scripts/sliderRange/sliderRange.yy",},},
{"id":{"name":"point_rect_overlap","path":"scripts/point_rect_overlap/point_rect_overlap.yy",},},
@ -1546,7 +1548,6 @@
{"id":{"name":"node_armature","path":"scripts/node_armature/node_armature.yy",},},
{"id":{"name":"node_array_length","path":"scripts/node_array_length/node_array_length.yy",},},
{"id":{"name":"node_erode","path":"scripts/node_erode/node_erode.yy",},},
{"id":{"name":"draw_circle_angle","path":"scripts/draw_circle_angle/draw_circle_angle.yy",},},
{"id":{"name":"node_wrap_mesh","path":"scripts/node_wrap_mesh/node_wrap_mesh.yy",},},
{"id":{"name":"node_surface_to_buffer","path":"scripts/node_surface_to_buffer/node_surface_to_buffer.yy",},},
{"id":{"name":"node_curve","path":"scripts/node_curve/node_curve.yy",},},
@ -1730,7 +1731,6 @@
{"id":{"name":"s_node_strandSim_update","path":"sprites/s_node_strandSim_update/s_node_strandSim_update.yy",},},
{"id":{"name":"async_functions","path":"scripts/async_functions/async_functions.yy",},},
{"id":{"name":"s_node_RGB_combine","path":"sprites/s_node_RGB_combine/s_node_RGB_combine.yy",},},
{"id":{"name":"draw_circle_prec","path":"scripts/draw_circle_prec/draw_circle_prec.yy",},},
{"id":{"name":"s_node_shadow_cast","path":"sprites/s_node_shadow_cast/s_node_shadow_cast.yy",},},
{"id":{"name":"fft_functions","path":"scripts/fft_functions/fft_functions.yy",},},
{"id":{"name":"path_function","path":"scripts/path_function/path_function.yy",},},

Binary file not shown.

View file

@ -10,6 +10,9 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
pose_angle = 0;
pose_scale = 1;
pose_posit = [ 0, 0 ];
pose_local_angle = 0;
pose_local_scale = 1;
pose_local_posit = [ 0, 0 ];
self.is_main = false;
self.parent_anchor = true;
@ -27,6 +30,7 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
updated = false;
IKlength = 0;
IKTarget = noone;
freeze_data = {};
@ -61,6 +65,19 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
childs[i].freeze();
}
static findBone = function(_id) {
if(id == _id)
return self;
for( var i = 0; i < array_length(childs); i++ ) {
var b = childs[i].findBone(_id);
if(b != noone)
return b;
}
return noone;
}
static getPoint = function(progress) {
var len = length * progress;
@ -80,7 +97,16 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
return p;
}
static draw = function(edit = false, _x = 0, _y = 0, _s = 1, _mx = 0, _my = 0, child = true, hovering = noone) {
static draw = function(edit = false, _x = 0, _y = 0, _s = 1, _mx = 0, _my = 0, hovering = noone, selecting = noone) {
var hover = _drawBone(edit, _x, _y, _s, _mx, _my, hovering, selecting);
drawControl();
return hover;
}
control_x0 = 0; control_y0 = 0; control_i0 = 0;
control_x1 = 0; control_y1 = 0; control_i1 = 0;
static _drawBone = function(edit = false, _x = 0, _y = 0, _s = 1, _mx = 0, _my = 0, hovering = noone, selecting = noone) {
var hover = noone;
var p0 = getPoint(0);
@ -91,25 +117,54 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
p1.x = _x + p1.x * _s;
p1.y = _y + p1.y * _s;
control_x0 = p0.x; control_y0 = p0.y;
control_x1 = p1.x; control_y1 = p1.y;
if(parent != noone) {
var _boneHover = hovering != noone && hovering[0] == self && hovering[1] == 2;
var aa = _boneHover? 1 : 0.75;
draw_set_color(_boneHover? c_white : COLORS._main_accent);
if(!parent_anchor && parent.parent != noone) {
var _p = parent.getPoint(0);
_p.x = _x + _p.x * _s;
_p.y = _y + _p.y * _s;
draw_line_dashed(_p.x, _p.y, p0.x, p0.y, 1);
if(hovering != noone && hovering[0] == self && hovering[1] == 2) {
draw_set_color(c_white);
draw_set_alpha(1);
} else if(selecting == self) {
draw_set_color(COLORS._main_value_positive);
draw_set_alpha(0.75);
} else {
draw_set_color(COLORS._main_accent);
draw_set_alpha(0.75);
}
draw_set_alpha(aa);
var _ppx = lerp(p0.x, p1.x, 0.2);
var _ppy = lerp(p0.y, p1.y, 0.2);
draw_line_width2(p0.x, p0.y, _ppx, _ppy, 2, 12);
draw_line_width2(_ppx, _ppy, p1.x, p1.y, 12, 2);
if(IKlength == 0) {
if(!parent_anchor && parent.parent != noone) {
var _p = parent.getPoint(0);
_p.x = _x + _p.x * _s;
_p.y = _y + _p.y * _s;
draw_line_dashed(_p.x, _p.y, p0.x, p0.y, 1);
}
var _ppx = lerp(p0.x, p1.x, 0.2);
var _ppy = lerp(p0.y, p1.y, 0.2);
draw_line_width2(p0.x, p0.y, _ppx, _ppy, 2, 12);
draw_line_width2(_ppx, _ppy, p1.x, p1.y, 12, 2);
if((edit & 0b100) && distance_to_line(_mx, _my, p0.x, p0.y, p1.x, p1.y) <= 12) //drag bone
hover = [ self, 2 ];
} else {
draw_set_color(c_white);
if(!parent_anchor && parent.parent != noone) {
var _p = parent.getPoint(1);
_p.x = _x + _p.x * _s;
_p.y = _y + _p.y * _s;
draw_line_dashed(_p.x, _p.y, p0.x, p0.y, 1);
}
draw_sprite_ui(THEME.preview_bone_IK, 0, p0.x, p0.y,,,, c_white, draw_get_alpha());
if((edit & 0b100) && point_in_circle(_mx, _my, p0.x, p0.y, 24))
hover = [ self, 2 ];
}
draw_set_alpha(1.00);
if(attributes.display_name) {
if(attributes.display_name && IKlength == 0) {
if(abs(p0.y - p1.y) < abs(p0.x - p1.x)) {
draw_set_text(f_p2, fa_center, fa_bottom, COLORS._main_accent);
draw_text_add((p0.x + p1.x) / 2, (p0.y + p1.y) / 2 - 4, name);
@ -119,33 +174,29 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
}
}
if(edit && distance_to_line(_mx, _my, p0.x, p0.y, p1.x, p1.y) <= 12) //drag bone
hover = [ self, 2 ];
if(IKlength == 0) {
if(!parent_anchor) {
control_i0 = (hovering != noone && hovering[0] == self && hovering[1] == 0)? 0 : 2;
if((edit & 0b001) && point_in_circle(_mx, _my, p0.x, p0.y, ui(16))) //drag head
hover = [ self, 0 ];
}
if(!parent_anchor) {
if(edit && point_in_circle(_mx, _my, p0.x, p0.y, ui(16))) { //drag head
draw_sprite_colored(THEME.anchor_selector, 0, p0.x, p0.y);
hover = [ self, 0 ];
} else
draw_sprite_colored(THEME.anchor_selector, 2, p0.x, p0.y);
control_i1 = (hovering != noone && hovering[0] == self && hovering[1] == 1)? 0 : 2;
if((edit & 0b010) && point_in_circle(_mx, _my, p1.x, p1.y, ui(16))) //drag tail
hover = [ self, 1 ];
}
if(edit && point_in_circle(_mx, _my, p1.x, p1.y, ui(16))) { //drag tail
draw_sprite_colored(THEME.anchor_selector, 0, p1.x, p1.y);
hover = [ self, 1 ];
} else
draw_sprite_colored(THEME.anchor_selector, 2, p1.x, p1.y);
}
//var ph = getPoint(0.5);
//ph.x = _x + ph.x * _s;
//ph.y = _y + ph.y * _s;
//draw_set_color(COLORS._main_accent);
//draw_circle(ph.x, ph.y, 4, false);
//draw_set_color(c_red);
//for( var i = 0; i < array_length(FABRIK_result); i++ ) {
// var pt = FABRIK_result[i];
// draw_circle(_x + pt.x * _s, _y + pt.y * _s, 16, false);
//}
if(child)
for( var i = 0; i < array_length(childs); i++ ) {
var h = childs[i].draw(edit, _x, _y, _s, _mx, _my, true, hovering);
var h = childs[i]._drawBone(edit, _x, _y, _s, _mx, _my, hovering, selecting);
if(hover == noone && h != noone)
hover = h;
}
@ -153,6 +204,17 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
return hover;
}
static drawControl = function() {
if(parent != noone && IKlength == 0) {
if(!parent_anchor)
draw_sprite_colored(THEME.anchor_selector, control_i0, control_x0, control_y0);
draw_sprite_colored(THEME.anchor_selector, control_i1, control_x1, control_y1);
}
for( var i = 0; i < array_length(childs); i++ )
childs[i].drawControl();
}
static resetPose = function() {
pose_angle = 0;
pose_scale = 1;
@ -174,6 +236,10 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
return;
}
pose_local_angle = pose_angle;
pose_local_scale = pose_scale;
pose_local_posit = pose_posit;
pose_posit[0] += _position[0];
pose_posit[1] += _position[1];
pose_angle += _angle;
@ -182,8 +248,8 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
var _x = lengthdir_x(distance, direction) + pose_posit[0];
var _y = lengthdir_y(distance, direction) + pose_posit[1];
direction = point_direction(0, 0, _x, _y);
distance = point_distance(0, 0, _x, _y);
direction = point_direction(0, 0, _x, _y) + _angle;
distance = point_distance(0, 0, _x, _y) * _scale;
angle += pose_angle;
length *= pose_scale;
@ -196,8 +262,126 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
}
}
static setIKconstrain = function() {
static setIKconstrain = function() {
if(IKlength > 0 && IKTarget != noone) {
var points = array_create(IKlength + 1);
var lengths = array_create(IKlength);
var bones = array_create(IKlength);
var bn = IKTarget;
for( var i = IKlength; i > 0; i-- ) {
var _p = bn.getPoint(1);
bones[i - 1] = bn;
points[i] = {
x: _p.x,
y: _p.y
};
bn = bn.parent;
}
_p = bn.getPoint(1);
points[0] = {
x: _p.x,
y: _p.y
};
for( var i = 0; i < IKlength; i++ ) {
var p0 = points[i];
var p1 = points[i + 1];
lengths[i] = point_distance(p0.x, p0.y, p1.x, p1.y);
}
var p = parent.getPoint(0, 0);
p.x += lengthdir_x(distance, direction);
p.y += lengthdir_y(distance, direction);
FABRIK(bones, points, lengths, p.x, p.y);
}
for( var i = 0; i < array_length(childs); i++ )
childs[i].setIKconstrain();
}
FABRIK_result = [];
static FABRIK = function(bones, points, lengths, dx, dy) {
var threshold = 0.1;
var _bo = array_create(array_length(points));
for( var i = 0; i < array_length(points); i++ )
_bo[i] = { x: points[i].x, y: points[i].y };
var sx = points[0].x;
var sy = points[0].y;
var itr = 0;
do {
FABRIK_backward(points, lengths, dx, dy);
FABRIK_forward(points, lengths, sx, sy);
var delta = 0;
var _bn = array_create(array_length(points));
for( var i = 0; i < array_length(points); i++ ) {
_bn[i] = { x: points[i].x, y: points[i].y };
delta += point_distance(_bo[i].x, _bo[i].y, _bn[i].x, _bn[i].y);
}
_bo = _bn;
if(++itr >= 32) break;
} until(delta <= threshold);
for( var i = 0; i < array_length(points) - 1; i++ ) {
var bone = bones[i];
var p0 = points[i];
var p1 = points[i + 1];
var dir = point_direction(p0.x, p0.y, p1.x, p1.y);
bone.angle = dir;
FABRIK_result[i] = p0;
}
FABRIK_result[i] = p1;
}
static FABRIK_backward = function(points, lengths, dx, dy) {
var tx = dx;
var ty = dy;
for( var i = array_length(points) - 1; i > 0; i-- ) {
var p1 = points[i];
var p0 = points[i - 1];
var len = lengths[i - 1];
var dir = point_direction(p0.x, p0.y, tx, ty);
p1.x = tx;
p1.y = ty;
p0.x = p1.x + lengthdir_x(len, dir);
p0.y = p1.y + lengthdir_y(len, dir);
tx = p0.x;
ty = p0.y;
}
}
static FABRIK_forward = function(points, lengths, sx, sy) {
var tx = sx;
var ty = sy;
for( var i = 0; i < array_length(points) - 1; i++ ) {
var p0 = points[i];
var p1 = points[i + 1];
var len = lengths[i];
var dir = point_direction(tx, ty, p1.x, p1.y);
p0.x = tx;
p0.y = ty;
p1.x = p0.x + lengthdir_x(len, dir);
p1.y = p0.y + lengthdir_y(len, dir);
tx = p1.x;
ty = p1.y;
}
}
static serialize = function() {
@ -213,6 +397,9 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
bone.is_main = is_main;
bone.parent_anchor = parent_anchor;
bone.IKlength = IKlength;
bone.IKTarget = IKTarget == noone? "" : IKTarget.id;
bone.childs = [];
for( var i = 0; i < array_length(childs); i++ )
bone.childs[i] = childs[i].serialize();
@ -234,6 +421,9 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
self.attributes = attributes;
self.node = node;
IKlength = bone.IKlength;
IKTarget = bone.IKTarget;
childs = [];
for( var i = 0; i < array_length(bone.childs); i++ ) {
var _b = new __Bone().deserialize(bone.childs[i], attributes, node);
@ -243,6 +433,16 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
return self;
}
static connect = function() {
if(parent == noone || IKTarget == "")
IKTarget = noone;
else if(is_string(IKTarget))
IKTarget = parent.findBone(IKTarget);
for( var i = 0; i < array_length(childs); i++ )
childs[i].connect();
}
static clone = function(attributes) {
var _b = new __Bone(parent, distance, direction, angle, length, attributes);
_b.id = id;
@ -250,10 +450,15 @@ function __Bone(parent = noone, distance = 0, direction = 0, angle = 0, length =
_b.is_main = is_main;
_b.parent_anchor = parent_anchor;
_b.IKlength = IKlength;
_b.IKTarget = IKTarget == noone? "" : IKTarget.id;
for( var i = 0; i < array_length(childs); i++ )
_b.addChild(childs[i].clone(attributes));
return _b;
}
static toString = function() {
return $"Bone {name} [{id}]";
}
}

View file

@ -1,40 +0,0 @@
function draw_circle_border(xx, yy, r, w) {
var step = 32;
var angle_step = 360 / step;
var px, py, _px, _py;
for(var i = 0; i <= step; i++){
var px = xx + lengthdir_x(r, i * angle_step);
var py = yy + lengthdir_y(r, i * angle_step);
if(i)
draw_line_round(_px, _py, px, py, w);
_px = px;
_py = py;
}
}
function draw_ellipse_border(x0, y0, x1, y1, w) {
var step = 32;
var angle_step = 360 / step;
var px, py, _px, _py;
var cx = (x0 + x1) / 2;
var cy = (y0 + y1) / 2;
var ww = abs(x0 - x1) / 2;
var hh = abs(y0 - y1) / 2;
for(var i = 0; i <= step; i++){
var px = cx + lengthdir_x(ww, i * angle_step);
var py = cy + lengthdir_y(hh, i * angle_step);
if(i)
draw_line_round(_px, _py, px, py, w);
_px = px;
_py = py;
}
}

View file

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

View file

@ -1,10 +1,56 @@
function draw_circle_prec(x, y, r, border, precision = 32) {
draw_set_circle_precision(precision);
draw_circle(x, y, r, border);
}
function draw_circle_border(xx, yy, r, w) {
var step = 32;
var angle_step = 360 / step;
var px, py, _px, _py;
for(var i = 0; i <= step; i++){
var px = xx + lengthdir_x(r, i * angle_step);
var py = yy + lengthdir_y(r, i * angle_step);
if(i)
draw_line_round(_px, _py, px, py, w);
_px = px;
_py = py;
}
}
function draw_ellipse_border(x0, y0, x1, y1, w) {
var step = 32;
var angle_step = 360 / step;
var px, py, _px, _py;
var cx = (x0 + x1) / 2;
var cy = (y0 + y1) / 2;
var ww = abs(x0 - x1) / 2;
var hh = abs(y0 - y1) / 2;
for(var i = 0; i <= step; i++){
var px = cx + lengthdir_x(ww, i * angle_step);
var py = cy + lengthdir_y(hh, i * angle_step);
if(i)
draw_line_round(_px, _py, px, py, w);
_px = px;
_py = py;
}
}
function draw_circle_angle(_x, _y, _r, _angSt, _angEd, precision = 32) {
var ox, oy, nx, ny, oa, na;
draw_primitive_begin(pr_trianglelist);
for( var i = 0; i <= precision; i++ ) {
na = lerp(_angSt, _angEd, i / precision);
na = lerp_float_angle(_angSt, _angEd, i / precision);
nx = _x + lengthdir_x(_r, na);
ny = _y + lengthdir_y(_r, na);

View file

@ -1,7 +1,7 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "draw_circle_angle",
"name": "draw_circle_functions",
"isCompatibility": false,
"isDnD": false,
"parent": {

View file

@ -1,4 +0,0 @@
function draw_circle_prec(x, y, r, border, precision = 32) {
draw_set_circle_precision(precision);
draw_circle(x, y, r, border);
}

View file

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

View file

@ -1,9 +1,15 @@
function draw_line_round(x1, y1, x2, y2, w) {
draw_line_width(x1, y1, x2, y2, w);
draw_set_circle_precision(8);
draw_circle(x1, y1, w/2, false);
draw_circle(x2, y2, w/2, false);
//draw_set_circle_precision(8);
//draw_circle(x1, y1, w/2, false);
//draw_circle(x2, y2, w/2, false);
var dir = point_direction(x1, y1, x2, y2) + 90;
draw_circle_angle(x1 + 1, y1 + 1, w / 2, dir, dir + 90);
draw_circle_angle(x1 + 1, y1 + 1, w / 2, dir + 90, dir + 180);
draw_circle_angle(x2 + 1, y2 + 1, w / 2, dir, dir - 90);
draw_circle_angle(x2 + 1, y2 + 1, w / 2, dir - 90, dir - 180);
}
function draw_line_round_color(x1, y1, x2, y2, w, c1, c2) {

View file

@ -14,7 +14,6 @@ function lerp_float(from, to, speed) {
}
function lerp_linear(from, to, speed) {
if(fps < 15) return to;
if(abs(from - to) < speed)
return to;
else
@ -31,8 +30,11 @@ function lerp_angle(from, to, speed) {
}
function lerp_angle_linear(from, to, speed) {
if(fps < 15) return to;
if(abs(angle_difference(to, from)) < speed) return to;
return from + sign(angle_difference(to, from)) * speed;
}
function lerp_float_angle(from, to, ratio) {
return from + angle_difference(to, from) * ratio;
}

View file

@ -38,22 +38,20 @@ function Node_Armature(_x, _y, _group = noone) : Node(_x, _y, _group) constructo
if(!bone.is_main) {
if(bone.parent_anchor)
draw_sprite_ui(THEME.bone, 1, __x + 12, ty + 12,,,, COLORS._main_icon);
draw_sprite_ui(THEME.bone, 1, __x + 12, ty + 14,,,, COLORS._main_icon);
else if(bone.IKlength)
draw_sprite_ui(THEME.bone, 2, __x + 12, ty + 14,,,, COLORS._main_icon);
else {
if(_hover && point_in_circle(_m[0], _m[1], __x + 12, ty + 12, 12)) {
draw_sprite_ui(THEME.bone, 0, __x + 12, ty + 12,,,, COLORS._main_icon_light);
draw_sprite_ui(THEME.bone, 0, __x + 12, ty + 14,,,, COLORS._main_icon_light);
if(mouse_press(mb_left, _focus))
bone_dragging = bone;
} else
draw_sprite_ui(THEME.bone, 0, __x + 12, ty + 12,,,, COLORS._main_icon);
draw_sprite_ui(THEME.bone, 0, __x + 12, ty + 14,,,, COLORS._main_icon);
}
draw_set_text(f_p2, fa_left, fa_center, COLORS._main_text);
draw_text(__x + 24, ty + 12, bone.name);
//if(bone_dragging != noone && point_in_rectangle(_m[0], _m[1], _x, ty, _x + _w, ty + _hh - 1)) {
// draw_sprite_stretched_ext(THEME.ui_panel_active, 0, _x, ty, _w, _hh, COLORS._main_accent, 1);
// hovering = bone;
//}
bone.tb_name.setFocusHover(_focus, _hover);
bone.tb_name.draw(__x + 24, ty + 3, __w - 24 - 32, _hh - 6, bone.name, _m);
ty += _hh;
@ -103,11 +101,10 @@ function Node_Armature(_x, _y, _group = noone) : Node(_x, _y, _group) constructo
})]);
tools = [
new NodeTool( "Transform", THEME.bone_tool_transform ),
new NodeTool( "Add bones", THEME.bone_tool_add ),
new NodeTool( "Remove bones", THEME.bone_tool_remove ),
new NodeTool( "Detach bones", THEME.bone_tool_detach ),
new NodeTool( "IK", THEME.bone_tool_detach ),
new NodeTool( "IK", THEME.bone_tool_IK ),
];
anchor_selecting = noone;
@ -119,6 +116,7 @@ function Node_Armature(_x, _y, _group = noone) : Node(_x, _y, _group) constructo
builder_my = 0;
bone_dragging = noone;
ik_dragging = noone;
moving = false;
scaling = false;
@ -127,127 +125,11 @@ function Node_Armature(_x, _y, _group = noone) : Node(_x, _y, _group) constructo
var mx = (_mx - _x) / _s;
var my = (_my - _y) / _s;
var _b = attributes.bones;
if(isUsingTool(0)) { //transform
attributes.bones.draw(false, _x, _y, _s, _mx, _my);
var _bst = ds_stack_create();
ds_stack_push(_bst, _b);
var minx = 999999;
var miny = 999999;
var maxx = -999999;
var maxy = -999999;
while(!ds_stack_empty(_bst)) {
var __b = ds_stack_pop(_bst);
if(!__b.is_main) {
var p0 = __b.getPoint(0);
var p1 = __b.getPoint(1);
minx = min(minx, p0.x);
miny = min(miny, p0.y);
maxx = max(maxx, p0.x);
maxy = max(maxy, p0.y);
minx = min(minx, p1.x);
miny = min(miny, p1.y);
maxx = max(maxx, p1.x);
maxy = max(maxy, p1.y);
}
for( var i = 0; i < array_length(__b.childs); i++ )
ds_stack_push(_bst, __b.childs[i]);
}
ds_stack_destroy(_bst);
var hvSc = false;
var hvMv = false;
if(moving) {
var dx = mx - builder_mx;
var dy = my - builder_my;
builder_mx = mx;
builder_my = my;
for( var i = 0; i < array_length(_b.childs); i++ ) {
var bone = _b.childs[i];
var _bx = lengthdir_x(bone.distance, bone.direction) + dx;
var _by = lengthdir_y(bone.distance, bone.direction) + dy;
bone.distance = point_distance(0, 0, _bx, _by);
bone.direction = point_direction(0, 0, _bx, _by);
}
if(mouse_release(mb_left))
moving = false;
} else if(scaling) {
var dir = point_direction(minx, miny, maxx, maxy);
var ss = 1 + dot_product(lengthdir_x(1, dir), lengthdir_y(1, dir), mx - builder_mx, my - builder_my);
var _bst = ds_stack_create();
ds_stack_push(_bst, _b);
while(!ds_stack_empty(_bst)) {
var __b = ds_stack_pop(_bst);
if(!__b.is_main) {
__b.distance = __b.freeze_data.distance * ss;
__b.length = __b.freeze_data.length * ss;
}
for( var i = 0; i < array_length(__b.childs); i++ )
ds_stack_push(_bst, __b.childs[i]);
}
ds_stack_destroy(_bst);
if(mouse_release(mb_left))
scaling = false;
} else {
if(point_in_circle(_mx, _my, maxx, maxy, 16)) {
hvSc = true;
if(mouse_press(mb_left)) {
attributes.bones.freeze();
builder_mx = mx;
builder_my = my;
scaling = true;
}
} else if(point_in_circle(_mx, _my, maxx, maxy, 16)) {
hvMv = true;
if(mouse_press(mb_left)) {
builder_mx = mx;
builder_my = my;
moving = true;
}
}
}
draw_sprite_colored(THEME.anchor_scale, hvSc, maxx, maxy);
draw_set_color(COLORS._main_accent);
draw_rectangle_border(minx, miny, maxx, maxy, hvMv);
triggerRender();
return;
}
anchor_selecting = attributes.bones.draw(active, _x, _y, _s, _mx, _my, true, anchor_selecting);
//if(is_array(anchor_selecting)) print(anchor_selecting[1])
var _b = attributes.bones;
if(builder_bone != noone) {
//draw_set_color(COLORS._main_accent);
//draw_circle(_x + builder_sx * _s, _y + builder_sy * _s, 8, false);
anchor_selecting = _b.draw(false, _x, _y, _s, _mx, _my, anchor_selecting);
var dir = point_direction(builder_sx, builder_sy, mx, my);
var dis = point_distance(builder_sx, builder_sy, mx, my);
@ -298,7 +180,8 @@ function Node_Armature(_x, _y, _group = noone) : Node(_x, _y, _group) constructo
par_anc.x = _x + par_anc.x * _s;
par_anc.y = _y + par_anc.y * _s;
if(!builder_bone.parent.is_main && point_in_circle(_mx, _my, par_anc.x, par_anc.y, 16) && mouse_release(mb_left))
var inRange = point_in_circle(_mx, _my, par_anc.x, par_anc.y, 16) && mouse_release(mb_left);
if(!builder_bone.parent.is_main && builder_bone.IKlength > 0 && inRange)
builder_bone.parent_anchor = true;
}
} else if(builder_type == 1) {
@ -313,9 +196,52 @@ function Node_Armature(_x, _y, _group = noone) : Node(_x, _y, _group) constructo
}
triggerRender();
}
} else if(ik_dragging != noone) {
anchor_selecting = _b.draw(active * 0b100, _x, _y, _s, _mx, _my, anchor_selecting, ik_dragging);
if(anchor_selecting != noone && anchor_selecting[1] == 2) {
var anc = anchor_selecting[0];
var reachable = false;
var _bone = ik_dragging.parent;
var len = 1;
while(_bone != noone) {
if(_bone == anc) {
reachable = true;
break;
}
len++;
_bone = _bone.parent;
}
if(reachable && mouse_release(mb_left)) {
var p1 = ik_dragging.getPoint(1);
var p0 = anc.getPoint(0);
var _len = point_distance(p0.x, p0.y, p1.x, p1.y);
var _ang = point_direction(p0.x, p0.y, p1.x, p1.y);
var IKbone = new __Bone(anc, _len, _ang, ik_dragging.angle + 90, 0, attributes, self);
anc.addChild(IKbone);
IKbone.IKlength = len;
IKbone.IKTarget = ik_dragging;
IKbone.name = "IK handle";
IKbone.parent_anchor = false;
}
}
if(mouse_release(mb_left)) {
ik_dragging = noone;
UNDO_HOLDING = false;
}
triggerRender();
} else if(isUsingTool(0)) { // builder
anchor_selecting = _b.draw(active * 0b111, _x, _y, _s, _mx, _my, anchor_selecting);
if(isUsingTool(1)) { // builder
if(mouse_press(mb_left, active)) {
if(anchor_selecting == noone) {
builder_bone = createBone(attributes.bones, point_distance(0, 0, mx, my), point_direction(0, 0, mx, my));
@ -351,28 +277,30 @@ function Node_Armature(_x, _y, _group = noone) : Node(_x, _y, _group) constructo
draw_sprite_ext(THEME.bone_tool_add, 1, _mx + 24, _my + 24, 1, 1, 0, c_white, 1);
} else if(anchor_selecting[1] == 2)
draw_sprite_ext(THEME.bone_tool_add, 0, _mx + 24, _my + 24, 1, 1, 0, c_white, 1);
} else if(isUsingTool(2)) { //remover
if(anchor_selecting != noone && anchor_selecting[0].parent != noone && mouse_press(mb_left, active)) {
} else if(isUsingTool(1)) { //remover
anchor_selecting = _b.draw(active * 0b100, _x, _y, _s, _mx, _my, anchor_selecting);
if(anchor_selecting != noone && anchor_selecting[1] == 2 && anchor_selecting[0].parent != noone && mouse_press(mb_left, active)) {
var _bone = anchor_selecting[0];
var _par = _bone.parent;
if(anchor_selecting[1] == 2) {
array_remove(_par.childs, _bone);
array_remove(_par.childs, _bone);
for( var i = 0; i < array_length(_bone.childs); i++ ) {
var _ch = _bone.childs[i];
_par.addChild(_ch);
for( var i = 0; i < array_length(_bone.childs); i++ ) {
var _ch = _bone.childs[i];
_par.addChild(_ch);
_ch.parent_anchor = _bone.parent_anchor;
}
triggerRender();
_ch.parent_anchor = _bone.parent_anchor;
}
triggerRender();
}
if(anchor_selecting != noone)
draw_sprite_ext(THEME.bone_tool_remove, 1, _mx + 24, _my + 24, 1, 1, 0, c_white, 1);
} else if(isUsingTool(3)) { //detach
} else if(isUsingTool(2)) { //detach
anchor_selecting = _b.draw(active * 0b100, _x, _y, _s, _mx, _my, anchor_selecting);
if(anchor_selecting != noone && anchor_selecting[1] == 2 && mouse_press(mb_left, active)) {
builder_bone = anchor_selecting[0];
builder_type = anchor_selecting[1];
@ -390,9 +318,15 @@ function Node_Armature(_x, _y, _group = noone) : Node(_x, _y, _group) constructo
builder_my = my;
UNDO_HOLDING = true;
}
} else if(isUsingTool(4)) { //IK
} else if(isUsingTool(3)) { //IK
anchor_selecting = _b.draw(active * 0b100, _x, _y, _s, _mx, _my, anchor_selecting);
if(anchor_selecting != noone && anchor_selecting[1] == 2 && mouse_press(mb_left, active)) {
ik_dragging = anchor_selecting[0];
}
} else { //mover
anchor_selecting = _b.draw(active * 0b111, _x, _y, _s, _mx, _my, anchor_selecting);
} else if(isNotUsingTool()) { //mover
if(anchor_selecting != noone && mouse_press(mb_left, active)) {
builder_bone = anchor_selecting[0];
builder_type = anchor_selecting[1];
@ -441,6 +375,7 @@ function Node_Armature(_x, _y, _group = noone) : Node(_x, _y, _group) constructo
if(!struct_has(load_map, "bones")) return;
attributes.bones = new __Bone(,,,,, attributes, self);
attributes.bones.deserialize(load_map.bones, attributes, self);
attributes.bones.connect();
}
static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) {

View file

@ -91,7 +91,13 @@ function Node_Armature_Bind(_x, _y, _group = noone) : Node_Processor(_x, _y, _gr
var __w = _st[2];
if(!bone.is_main) {
draw_sprite_ui(THEME.bone, bone.parent_anchor, __x + 12, ty + 12,,,, COLORS._main_icon);
if(bone.parent_anchor)
draw_sprite_ui(THEME.bone, 1, __x + 12, ty + 14,,,, COLORS._main_icon);
else if(bone.IKlength)
draw_sprite_ui(THEME.bone, 2, __x + 12, ty + 14,,,, COLORS._main_icon);
else
draw_sprite_ui(THEME.bone, 0, __x + 12, ty + 14,,,, COLORS._main_icon);
draw_set_text(f_p2, fa_left, fa_center, COLORS._main_text);
draw_text(__x + 24, ty + 12, bone.name);

View file

@ -104,6 +104,7 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const
posing_type = 0;
posing_sx = 0;
posing_sy = 0;
posing_sz = 0;
posing_mx = 0;
posing_my = 0;
@ -111,15 +112,17 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const
var _b = outputs[| 0].getValue();
if(_b == noone) return;
anchor_selecting = _b.draw(active, _x, _y, _s, _mx, _my, true, anchor_selecting);
anchor_selecting = _b.draw(active * 0b111, _x, _y, _s, _mx, _my, anchor_selecting);
var mx = (_mx - _x) / _s;
var my = (_my - _y) / _s;
if(posing_bone) {
if(posing_type == 0) { //move
var bx = posing_sx + (mx - posing_mx);
var by = posing_sy + (my - posing_my);
var ang = posing_bone.pose_angle;
var pp = point_rotate(mx - posing_mx, my - posing_my, 0, 0, -ang);
var bx = posing_sx + pp[0];
var by = posing_sy + pp[1];
var val = posing_input.getValue();
val[TRANSFORM.pos_x] = bx;
@ -129,11 +132,15 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const
} else if(posing_type == 1) { //scale
var ss = point_distance(posing_mx, posing_my, mx, my) / posing_sx;
var rot = point_direction(posing_mx, posing_my, mx, my) - posing_sy;
var ori = posing_bone.getPoint(0);
var ang = point_direction(ori.x, ori.y, mx, my);
var rot = angle_difference(ang, posing_sz);
posing_sz = ang;
posing_sy += rot;
var val = posing_input.getValue();
val[TRANSFORM.sca_x] = ss;
val[TRANSFORM.rot] = rot;
val[TRANSFORM.rot] = posing_sy;
if(posing_input.setValue(val))
UNDO_HOLDING = true;
@ -159,7 +166,7 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const
}
if(anchor_selecting != noone && mouse_press(mb_left, active)) {
if(anchor_selecting[1] == 0) { // move
if(anchor_selecting[1] == 0 || anchor_selecting[0].IKlength) { // move
posing_bone = anchor_selecting[0];
if(!ds_map_exists(boneMap, posing_bone.id))
setBone();
@ -180,9 +187,11 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const
posing_input = boneMap[? posing_bone.id];
posing_type = 1;
var ori = posing_bone.getPoint(0);
var val = posing_input.getValue();
posing_sx = posing_bone.length / posing_bone.pose_scale;
posing_sy = posing_bone.angle - posing_bone.pose_angle;
posing_sx = posing_bone.length / posing_bone.pose_local_scale;
posing_sy = val[TRANSFORM.rot];
posing_sz = point_direction(ori.x, ori.y, mx, my);
var pnt = posing_bone.getPoint(0);
posing_mx = pnt.x;
@ -226,6 +235,8 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const
if(_b == noone) return;
var _bone_pose = _b.clone(attributes);
_bone_pose.connect();
_bone_pose.resetPose();
var _bst = ds_stack_create();
ds_stack_push(_bst, _bone_pose);

View file

@ -2,7 +2,7 @@
global.EQUATION_PRES = ds_map_create();
global.EQUATION_PRES[? "+"] = 1;
global.EQUATION_PRES[? "-"] = 1;
global.EQUATION_PRES[? "_"] = 9; //unary negative
global.EQUATION_PRES[? ""] = 9; //unary negative
global.EQUATION_PRES[? "*"] = 2;
global.EQUATION_PRES[? "/"] = 2;
global.EQUATION_PRES[? "$"] = 3;
@ -162,7 +162,7 @@ function functionStringClean(fx) {
return v1 + v2;
return 0;
case "-": return (is_real(v1) && is_real(v2))? v1 - v2 : 0;
case "_": return is_real(v1)? -v1 : 0;
case "": return is_real(v1)? -v1 : 0;
case "*": return (is_real(v1) && is_real(v2))? v1 * v2 : 0;
case "$": return (is_real(v1) && is_real(v2))? power(v1, v2) : 0;
case "/": return (is_real(v1) && is_real(v2))? v1 / v2 : 0;
@ -226,7 +226,7 @@ function functionStringClean(fx) {
else {
if(pres[? ch] > pres[? ds_stack_top(op)] || ds_stack_top(op) == "(") ds_stack_push(op, ch);
else {
if(ch == "-" && ds_map_exists(pres, _ch)) ch = "_"; //unary negative
if(ch == "-" && ds_map_exists(pres, _ch)) ch = ""; //unary negative
while(pres[? ch] <= pres[? ds_stack_top(op)] && !ds_stack_empty(op))
ds_stack_push(vl, buildFuncTree(ds_stack_pop(op), vl));
@ -308,7 +308,7 @@ function functionStringClean(fx) {
if(ds_stack_empty(vl)) return noone;
switch(operator) {
case "-": //deal with preceeding megative number -5
case "-": //deal with preceeding negative number -5
if(ds_stack_size(vl) >= 2) {
var _v1 = ds_stack_pop(vl);
var _v2 = ds_stack_pop(vl);