From 52ce0129e7bb1c3aacd46987a89f3912d43c5f72 Mon Sep 17 00:00:00 2001 From: Tanasart Date: Wed, 18 Dec 2024 14:33:59 +0700 Subject: [PATCH] [Armature Pose] Hold alt key to lock children rotation and scale. --- scripts/__bone/__bone.gml | 21 +-- scripts/node_armature/node_armature.gml | 3 + .../node_armature_pose/node_armature_pose.gml | 124 +++++++++++++----- 3 files changed, 107 insertions(+), 41 deletions(-) diff --git a/scripts/__bone/__bone.gml b/scripts/__bone/__bone.gml index 627d1c20d..2281684b2 100644 --- a/scripts/__bone/__bone.gml +++ b/scripts/__bone/__bone.gml @@ -260,10 +260,13 @@ function __Bone(_parent = noone, _distance = 0, _direction = 0, _angle = 0, _len _bone_bbox ??= bbox(); if(!is_main && is_array(_bone_bbox)) { - var boxs = min(_bbox.w / _bone_bbox[4], _bbox.h / _bone_bbox[5]); + var _bw = max(1, _bone_bbox[4]); + var _bh = max(1, _bone_bbox[5]); - _bbox.w = boxs * _bone_bbox[4]; - _bbox.h = boxs * _bone_bbox[5]; + var boxs = min(_bbox.w / _bw, _bbox.h / _bh); + + _bbox.w = boxs * _bw; + _bbox.h = boxs * _bh; _bbox.x0 = _bbox.xc - _bbox.w / 2; _bbox.x1 = _bbox.xc + _bbox.w / 2; @@ -271,10 +274,10 @@ function __Bone(_parent = noone, _distance = 0, _direction = 0, _angle = 0, _len _bbox.y0 = _bbox.yc - _bbox.h / 2; _bbox.y1 = _bbox.yc + _bbox.h / 2; - var p0x = _bbox.x0 + _bbox.w * (bone_head_pose.x - _bone_bbox[0]) / _bone_bbox[4]; - var p0y = _bbox.y0 + _bbox.h * (bone_head_pose.y - _bone_bbox[1]) / _bone_bbox[5]; - var p1x = _bbox.x0 + _bbox.w * (bone_tail_pose.x - _bone_bbox[0]) / _bone_bbox[4]; - var p1y = _bbox.y0 + _bbox.h * (bone_tail_pose.y - _bone_bbox[1]) / _bone_bbox[5]; + var p0x = _bbox.x0 + _bbox.w * (bone_head_pose.x - _bone_bbox[0]) / _bw; + var p0y = _bbox.y0 + _bbox.h * (bone_head_pose.y - _bone_bbox[1]) / _bh; + var p1x = _bbox.x0 + _bbox.w * (bone_tail_pose.x - _bone_bbox[0]) / _bw; + var p1y = _bbox.y0 + _bbox.h * (bone_tail_pose.y - _bone_bbox[1]) / _bh; draw_set_circle_precision(8); @@ -381,8 +384,8 @@ function __Bone(_parent = noone, _distance = 0, _direction = 0, _angle = 0, _len if(parent) { // do this instead of recursion. pose_local_posit = parent.pose_apply_posit; - pose_local_rotate = parent.pose_apply_rotate; - pose_local_scale = parent.pose_apply_scale; + pose_local_rotate = apply_rotation? parent.pose_apply_rotate : 0; + pose_local_scale = apply_scale? parent.pose_apply_scale : 1; pose_apply_posit[0] += pose_local_posit[0]; pose_apply_posit[1] += pose_local_posit[1]; diff --git a/scripts/node_armature/node_armature.gml b/scripts/node_armature/node_armature.gml index 8cea6b40a..32b2f5717 100644 --- a/scripts/node_armature/node_armature.gml +++ b/scripts/node_armature/node_armature.gml @@ -879,6 +879,9 @@ function Node_Armature(_x, _y, _group = noone) : Node(_x, _y, _group) constructo ds_stack_destroy(_bst); if(minx == 9999999) return noone; + if(abs(maxx - minx) < 1) maxx = minx + 1; + if(abs(maxy - miny) < 1) maxy = miny + 1; + return BBOX().fromPoints(minx, miny, maxx, maxy); } diff --git a/scripts/node_armature_pose/node_armature_pose.gml b/scripts/node_armature_pose/node_armature_pose.gml index cd28ddcaf..c2abc022a 100644 --- a/scripts/node_armature_pose/node_armature_pose.gml +++ b/scripts/node_armature_pose/node_armature_pose.gml @@ -72,28 +72,30 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const tools = []; anchor_selecting = noone; - posing_bone = noone; - posing_input = 0; - posing_type = 0; + posing_bone = noone; + posing_input = 0; + posing_type = 0; + pose_child_lock = false; - posing_sx = 0; - posing_sy = 0; - posing_mx = 0; - posing_my = 0; + posing_sx = 0; + posing_sy = 0; + posing_mx = 0; + posing_my = 0; + + ////- Preview static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { var _b = inputs[0].getValue(); if(_b == noone || bonePose == noone) return; - var _hov = noone, hh, cc, aa; + var _hov = noone; var _bhov = anchor_selecting; for( var i = 0, n = array_length(boneArray); i < n; i++ ) { - var _bne = boneArray[i]; - var _sel = false; - - cc = c_white; + var _bne = boneArray[i]; + var _sel = false; + var cc = c_white; if(struct_has(boneMap, _bne.ID)) { var _inp = boneMap[$ _bne.ID]; @@ -103,8 +105,7 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const _bhov = [ _bne, 2 ]; } - hh = _bne.drawBone(attributes, _sel * active * 0b111, _x, _y, _s, _mx, _my, _bhov, posing_bone, cc, .5 + .5 * _sel); - + var hh = _bne.drawBone(attributes, _sel * active * 0b111, _x, _y, _s, _mx, _my, _bhov, posing_bone, cc, .5 + .5 * _sel); if(hh != noone && (_hov == noone || _bne.IKlength)) _hov = hh; } @@ -149,11 +150,28 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const var _direction = point_direction(posing_sx, posing_sy, smx, smy); var _distance = point_distance(posing_sx, posing_sy, smx, smy); - var _scale = _distance / (posing_bone.length * posing_bone.pose_local_scale); - var _rotation = _direction - (posing_bone.angle + posing_bone.pose_local_rotate); + var _orot = val[TRANSFORM.rot]; + var _osca = val[TRANSFORM.sca_x]; + var _nrot = _direction - (posing_bone.angle + posing_bone.pose_local_rotate); + var _nsca = _distance / (posing_bone.length * posing_bone.pose_local_scale); - val[TRANSFORM.sca_x] = _scale; - val[TRANSFORM.rot] = _rotation; + val[TRANSFORM.rot] = _nrot; + val[TRANSFORM.sca_x] = _nsca; + + if(pose_child_lock) { + var _dr = angle_difference(_nrot, _orot); + var _ds = _nsca / _osca; + + for( var i = 0, n = array_length(posing_bone.childs); i < n; i++ ) { + var _child = posing_bone.childs[i]; + + var _input = boneMap[$ _child.ID]; + var _val = array_clone(_input.getValue()); + if(_child.apply_rotation) _val[TRANSFORM.rot] -= _dr; + if(_child.apply_scale) _val[TRANSFORM.sca_x] /= _ds; + _input.setValue(_val); + } + } orig = posing_bone.getTail(); var _rx = _x + _s * orig.x; @@ -164,21 +182,44 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const var ori = posing_bone.getHead(); var ang = point_direction(ori.x, ori.y, mx, my); var rot = angle_difference(ang, posing_sy); - posing_sy = ang; + posing_sy = ang; posing_sx += rot; val[TRANSFORM.rot] = posing_sx; + if(pose_child_lock && rot != 0) + for( var i = 0, n = array_length(posing_bone.childs); i < n; i++ ) { + var _child = posing_bone.childs[i]; + if(!_child.apply_rotation) continue; + + var _input = boneMap[$ _child.ID]; + var _val = array_clone(_input.getValue()); + _val[TRANSFORM.rot] -= rot; + _input.setValue(_val); + } + orig = posing_bone.getHead(); var _rx = _x + _s * orig.x; var _ry = _y + _s * orig.y; draw_sprite_ext(s_bone_rotate, 0, _rx, _ry, 1, 1, posing_bone.pose_angle, COLORS._main_value_positive, 1); - - } else if(posing_type == 3) { //scale - var ss = point_distance(posing_mx, posing_my, smx, smy) / posing_sx; + } else if(posing_type == 3) { //scale + var ps = val[TRANSFORM.sca_x]; + var ss = point_distance(posing_mx, posing_my, smx, smy) / posing_sx; + var ds = ss / ps; val[TRANSFORM.sca_x] = ss; + if(pose_child_lock && ds != 1 && ds != 0) + for( var i = 0, n = array_length(posing_bone.childs); i < n; i++ ) { + var _child = posing_bone.childs[i]; + if(!_child.apply_scale) continue; + + var _input = boneMap[$ _child.ID]; + var _val = array_clone(_input.getValue()); + _val[TRANSFORM.sca_x] /= ds; + _input.setValue(_val); + } + orig = posing_bone.getPoint(0.8); var _rx = _x + _s * orig.x; var _ry = _y + _s * orig.y; @@ -206,6 +247,7 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const } else if(anchor_selecting != noone) { var _bne = anchor_selecting[0]; var _typ = anchor_selecting[1]; + var _lck = key_mod_press(ALT); if(_bne.IKlength) _typ = 0; @@ -240,11 +282,28 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const } } + if(_lck) { + for( var i = 0, n = array_length(_bne.childs); i < n; i++ ) { + var _ch = _bne.childs[i]; + var _bc = _ch.getPoint(0.5); + var _cx = _x + _s * _bc.x; + var _cy = _y + _s * _bc.y; + + BLEND_SUBTRACT + draw_set_color(c_white); + draw_circle(_cx, _cy, 16, false); + + BLEND_NORMAL + draw_sprite_ext(THEME.lock, 0, _cx, _cy, 1, 1, 0, COLORS._main_accent, 1); + } + } + gpu_set_texfilter(false); if(mouse_press(mb_left, active)) { - posing_bone = _bne; - posing_type = _typ; + posing_bone = _bne; + posing_type = _typ; + pose_child_lock = _lck; if(!struct_exists(boneMap, _bne.ID)) setBone(); posing_input = boneMap[$ _bne.ID]; @@ -289,18 +348,14 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const } } + ////- Update + static update = function(frame = CURRENT_FRAME) { var _b = getInputData(0); - if(_b == noone) { - boneHash = ""; - return; - } + if(_b == noone) { boneHash = ""; return; } var _h = _b.getHash(); - if(boneHash != _h) { - boneHash = _h; - setBone(); - } + if(boneHash != _h) { boneHash = _h; setBone(); } bonePose.resetPose() .setPosition(); @@ -337,6 +392,8 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const outputs[0].setValue(bonePose); } + ////- Draw + static getPreviewBoundingBox = function() { var minx = 9999999; var miny = 9999999; @@ -369,6 +426,9 @@ function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) const ds_stack_destroy(_bst); if(minx == 9999999) return noone; + if(abs(maxx - minx) < 1) maxx = minx + 1; + if(abs(maxy - miny) < 1) maxy = miny + 1; + return BBOX().fromPoints(minx, miny, maxx, maxy); }