2023-06-20 19:43:19 +02:00
|
|
|
function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
|
|
|
|
name = "Armature Pose";
|
|
|
|
|
2023-06-25 20:12:17 +02:00
|
|
|
w = 96;
|
|
|
|
h = 72;
|
|
|
|
min_h = h;
|
|
|
|
|
2023-06-23 15:39:24 +02:00
|
|
|
inputs[| 0] = nodeValue("Armature", self, JUNCTION_CONNECT.input, VALUE_TYPE.armature, noone)
|
|
|
|
.setVisible(true, true);
|
2023-06-20 19:43:19 +02:00
|
|
|
|
2023-06-21 20:36:53 +02:00
|
|
|
input_display_list = [ 0,
|
|
|
|
["Bones", false]
|
|
|
|
]
|
|
|
|
|
2023-08-05 14:00:33 +02:00
|
|
|
setIsDynamicInput(1);
|
2023-06-20 19:43:19 +02:00
|
|
|
|
|
|
|
outputs[| 0] = nodeValue("Armature", self, JUNCTION_CONNECT.output, VALUE_TYPE.armature, noone);
|
|
|
|
|
2023-06-21 20:36:53 +02:00
|
|
|
boneMap = ds_map_create();
|
|
|
|
|
|
|
|
attributes.display_name = true;
|
2023-07-05 15:09:52 +02:00
|
|
|
attributes.display_bone = 0;
|
|
|
|
|
|
|
|
array_push(attributeEditors, "Display");
|
2023-07-14 20:34:35 +02:00
|
|
|
array_push(attributeEditors, ["Display name", function() { return attributes.display_name; },
|
2023-06-21 20:36:53 +02:00
|
|
|
new checkBox(function() {
|
|
|
|
attributes.display_name = !attributes.display_name;
|
|
|
|
})]);
|
2023-07-14 20:34:35 +02:00
|
|
|
array_push(attributeEditors, ["Display bone", function() { return attributes.display_bone; },
|
2023-07-05 15:09:52 +02:00
|
|
|
new scrollBox(["Octahedral", "Stick"], function(ind) {
|
|
|
|
attributes.display_bone = ind;
|
|
|
|
})]);
|
2023-06-21 20:36:53 +02:00
|
|
|
|
2023-09-14 16:29:39 +02:00
|
|
|
static createNewInput = function(bone = noone) { #region
|
2023-06-21 20:36:53 +02:00
|
|
|
var index = ds_list_size(inputs);
|
|
|
|
|
|
|
|
inputs[| index] = nodeValue(bone != noone? bone.name : "bone", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0, 0, 1 ] )
|
|
|
|
.setDisplay(VALUE_DISPLAY.transform);
|
2023-10-02 08:57:44 +02:00
|
|
|
inputs[| index].display_data.bone_id = bone != noone? bone.ID : noone;
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
if(bone != noone)
|
2023-07-05 15:09:52 +02:00
|
|
|
boneMap[? bone.ID] = inputs[| index];
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
array_push(input_display_list, index);
|
2023-06-23 15:39:24 +02:00
|
|
|
|
|
|
|
return inputs[| index];
|
2023-09-14 16:29:39 +02:00
|
|
|
} #endregion
|
2023-06-21 20:36:53 +02:00
|
|
|
|
2023-06-23 15:39:24 +02:00
|
|
|
static setBone = function() { #region
|
|
|
|
//print("Setting dem bones...");
|
2023-10-02 08:57:44 +02:00
|
|
|
var _b = getInputData(0);
|
2023-06-21 20:36:53 +02:00
|
|
|
if(_b == noone) return;
|
|
|
|
|
|
|
|
var _bones = [];
|
|
|
|
var _bst = ds_stack_create();
|
|
|
|
ds_stack_push(_bst, _b);
|
|
|
|
|
|
|
|
while(!ds_stack_empty(_bst)) {
|
|
|
|
var __b = ds_stack_pop(_bst);
|
|
|
|
|
2023-07-25 20:12:40 +02:00
|
|
|
for( var i = 0, n = array_length(__b.childs); i < n; i++ ) {
|
2023-06-21 20:36:53 +02:00
|
|
|
array_push(_bones, __b.childs[i]);
|
|
|
|
ds_stack_push(_bst, __b.childs[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ds_stack_destroy(_bst);
|
2023-06-23 15:39:24 +02:00
|
|
|
//print($"Bone counts: {array_length(_bones)}");
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
var _inputs = ds_list_create();
|
|
|
|
_inputs[| 0] = inputs[| 0];
|
|
|
|
|
|
|
|
var _input_display_list = [
|
|
|
|
input_display_list[0],
|
|
|
|
input_display_list[1]
|
|
|
|
];
|
|
|
|
|
2023-07-25 20:12:40 +02:00
|
|
|
for( var i = 0, n = array_length(_bones); i < n; i++ ) {
|
2023-06-21 20:36:53 +02:00
|
|
|
var bone = _bones[i];
|
2023-06-23 15:39:24 +02:00
|
|
|
var _idx = ds_list_size(_inputs);
|
|
|
|
array_push(_input_display_list, _idx);
|
2023-07-05 15:09:52 +02:00
|
|
|
//print($" > Adding bone ID: {bone.ID}");
|
2023-06-23 15:39:24 +02:00
|
|
|
|
2023-07-05 15:09:52 +02:00
|
|
|
if(ds_map_exists(boneMap, bone.ID)) {
|
|
|
|
var _inp = boneMap[? bone.ID];
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
_inp.index = _idx;
|
|
|
|
ds_list_add(_inputs, _inp);
|
2023-06-23 15:39:24 +02:00
|
|
|
} else {
|
2023-08-05 14:00:33 +02:00
|
|
|
var _inp = createNewInput(bone);
|
2023-06-23 15:39:24 +02:00
|
|
|
ds_list_add(_inputs, _inp);
|
|
|
|
}
|
2023-06-21 20:36:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ds_list_destroy(inputs);
|
|
|
|
inputs = _inputs;
|
|
|
|
input_display_list = _input_display_list;
|
2023-06-23 15:39:24 +02:00
|
|
|
|
|
|
|
//print(_input_display_list);
|
2023-09-14 16:29:39 +02:00
|
|
|
} #endregion
|
2023-06-21 20:36:53 +02:00
|
|
|
|
2023-06-20 19:43:19 +02:00
|
|
|
tools = [
|
|
|
|
|
|
|
|
];
|
|
|
|
|
2023-06-21 20:36:53 +02:00
|
|
|
anchor_selecting = noone;
|
|
|
|
posing_bone = noone;
|
|
|
|
posing_input = 0;
|
|
|
|
posing_type = 0;
|
|
|
|
posing_sx = 0;
|
|
|
|
posing_sy = 0;
|
2023-06-26 18:55:41 +02:00
|
|
|
posing_sz = 0;
|
2023-06-21 20:36:53 +02:00
|
|
|
posing_mx = 0;
|
|
|
|
posing_my = 0;
|
|
|
|
|
2023-09-14 16:29:39 +02:00
|
|
|
static drawOverlay = function(active, _x, _y, _s, _mx, _my, _snx, _sny) { #region
|
2023-06-21 20:36:53 +02:00
|
|
|
var _b = outputs[| 0].getValue();
|
|
|
|
if(_b == noone) return;
|
|
|
|
|
2023-07-05 15:09:52 +02:00
|
|
|
anchor_selecting = _b.draw(attributes, active * 0b111, _x, _y, _s, _mx, _my, anchor_selecting);
|
2023-06-20 19:43:19 +02:00
|
|
|
|
2023-06-21 20:36:53 +02:00
|
|
|
var mx = (_mx - _x) / _s;
|
|
|
|
var my = (_my - _y) / _s;
|
|
|
|
|
2023-08-01 19:21:51 +02:00
|
|
|
var smx = value_snap(mx, _snx);
|
|
|
|
var smy = value_snap(my, _sny);
|
|
|
|
|
2023-09-14 16:29:39 +02:00
|
|
|
if(posing_bone) { #region
|
2023-07-10 20:14:10 +02:00
|
|
|
if(posing_type == 0 && posing_bone.parent) { //move
|
|
|
|
var ang = posing_bone.parent.pose_angle;
|
2023-08-01 19:21:51 +02:00
|
|
|
var pp = point_rotate(smx - posing_mx, smy - posing_my, 0, 0, -ang);
|
|
|
|
var bx = posing_sx + pp[0];
|
|
|
|
var by = posing_sy + pp[1];
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
var val = posing_input.getValue();
|
|
|
|
val[TRANSFORM.pos_x] = bx;
|
|
|
|
val[TRANSFORM.pos_y] = by;
|
|
|
|
if(posing_input.setValue(val))
|
|
|
|
UNDO_HOLDING = true;
|
|
|
|
|
2023-06-23 15:39:24 +02:00
|
|
|
} else if(posing_type == 1) { //scale
|
2023-08-01 19:21:51 +02:00
|
|
|
var ss = point_distance(posing_mx, posing_my, smx, smy) / posing_sx;
|
2023-06-26 18:55:41 +02:00
|
|
|
var ori = posing_bone.getPoint(0);
|
2023-08-01 19:21:51 +02:00
|
|
|
var ang = point_direction(ori.x, ori.y, smx, smy);
|
|
|
|
var rot = ang - posing_sy;
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
var val = posing_input.getValue();
|
|
|
|
val[TRANSFORM.sca_x] = ss;
|
2023-08-01 19:21:51 +02:00
|
|
|
val[TRANSFORM.rot] = rot;
|
2023-06-21 20:36:53 +02:00
|
|
|
if(posing_input.setValue(val))
|
|
|
|
UNDO_HOLDING = true;
|
|
|
|
|
2023-06-23 15:39:24 +02:00
|
|
|
} else if(posing_type == 2) { //rotate
|
2023-06-25 20:12:17 +02:00
|
|
|
var ori = posing_bone.getPoint(0);
|
2023-06-23 15:39:24 +02:00
|
|
|
var ang = point_direction(ori.x, ori.y, mx, my);
|
|
|
|
var rot = angle_difference(ang, posing_sy);
|
|
|
|
posing_sy = ang;
|
|
|
|
posing_sx += rot;
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
var val = posing_input.getValue();
|
2023-06-23 15:39:24 +02:00
|
|
|
val[TRANSFORM.rot] = posing_sx;
|
2023-08-08 18:45:00 +02:00
|
|
|
|
2023-06-21 20:36:53 +02:00
|
|
|
if(posing_input.setValue(val))
|
|
|
|
UNDO_HOLDING = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(mouse_release(mb_left)) {
|
|
|
|
posing_bone = noone;
|
2023-06-23 15:39:24 +02:00
|
|
|
posing_type = noone;
|
2023-06-21 20:36:53 +02:00
|
|
|
UNDO_HOLDING = false;
|
|
|
|
}
|
2023-09-14 16:29:39 +02:00
|
|
|
} #endregion
|
2023-06-21 20:36:53 +02:00
|
|
|
|
2023-09-14 16:29:39 +02:00
|
|
|
if(anchor_selecting != noone && mouse_press(mb_left, active)) { #region
|
2023-06-26 18:55:41 +02:00
|
|
|
if(anchor_selecting[1] == 0 || anchor_selecting[0].IKlength) { // move
|
2023-06-21 20:36:53 +02:00
|
|
|
posing_bone = anchor_selecting[0];
|
2023-07-05 15:09:52 +02:00
|
|
|
if(!ds_map_exists(boneMap, posing_bone.ID))
|
2023-06-21 20:36:53 +02:00
|
|
|
setBone();
|
2023-07-05 15:09:52 +02:00
|
|
|
posing_input = boneMap[? posing_bone.ID];
|
2023-06-21 20:36:53 +02:00
|
|
|
posing_type = 0;
|
|
|
|
|
|
|
|
var val = posing_input.getValue();
|
|
|
|
posing_sx = val[TRANSFORM.pos_x];
|
|
|
|
posing_sy = val[TRANSFORM.pos_y];
|
|
|
|
|
2023-08-01 19:21:51 +02:00
|
|
|
var _p = anchor_selecting[2];
|
|
|
|
posing_mx = (_p.x - _x) / _s;
|
|
|
|
posing_my = (_p.y - _y) / _s;
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
} else if(anchor_selecting[1] == 1) { // scale
|
|
|
|
posing_bone = anchor_selecting[0];
|
2023-07-05 15:09:52 +02:00
|
|
|
if(!ds_map_exists(boneMap, posing_bone.ID))
|
2023-06-21 20:36:53 +02:00
|
|
|
setBone();
|
2023-07-05 15:09:52 +02:00
|
|
|
posing_input = boneMap[? posing_bone.ID];
|
2023-06-21 20:36:53 +02:00
|
|
|
posing_type = 1;
|
|
|
|
|
2023-06-26 18:55:41 +02:00
|
|
|
var ori = posing_bone.getPoint(0);
|
2023-06-21 20:36:53 +02:00
|
|
|
var val = posing_input.getValue();
|
2023-06-26 18:55:41 +02:00
|
|
|
posing_sx = posing_bone.length / posing_bone.pose_local_scale;
|
2023-08-01 19:21:51 +02:00
|
|
|
posing_sy = posing_bone.angle - posing_bone.pose_local_angle;
|
|
|
|
posing_sz = point_direction(ori.x, ori.y, smx, smy);
|
2023-06-21 20:36:53 +02:00
|
|
|
|
2023-06-25 20:12:17 +02:00
|
|
|
var pnt = posing_bone.getPoint(0);
|
2023-06-23 15:39:24 +02:00
|
|
|
posing_mx = pnt.x;
|
|
|
|
posing_my = pnt.y;
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
} else if(anchor_selecting[1] == 2) { // rotate
|
|
|
|
posing_bone = anchor_selecting[0];
|
2023-07-05 15:09:52 +02:00
|
|
|
if(!ds_map_exists(boneMap, posing_bone.ID))
|
2023-06-21 20:36:53 +02:00
|
|
|
setBone();
|
2023-07-05 15:09:52 +02:00
|
|
|
posing_input = boneMap[? posing_bone.ID];
|
2023-06-21 20:36:53 +02:00
|
|
|
posing_type = 2;
|
|
|
|
|
2023-06-25 20:12:17 +02:00
|
|
|
var ori = posing_bone.getPoint(0);
|
2023-06-21 20:36:53 +02:00
|
|
|
var val = posing_input.getValue();
|
2023-06-23 15:39:24 +02:00
|
|
|
posing_sx = val[TRANSFORM.rot];
|
|
|
|
posing_sy = point_direction(ori.x, ori.y, mx, my);
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
posing_mx = mx;
|
|
|
|
posing_my = my;
|
|
|
|
}
|
2023-09-14 16:29:39 +02:00
|
|
|
} #endregion
|
|
|
|
} #endregion
|
2023-06-21 20:36:53 +02:00
|
|
|
|
2023-06-23 15:39:24 +02:00
|
|
|
bone_prev = noone;
|
2023-09-14 16:29:39 +02:00
|
|
|
static step = function() { #region
|
2023-10-02 08:57:44 +02:00
|
|
|
var _b = getInputData(0);
|
2023-06-21 20:36:53 +02:00
|
|
|
if(_b == noone) return;
|
2023-06-23 15:39:24 +02:00
|
|
|
if(bone_prev != _b) {
|
|
|
|
setBone();
|
|
|
|
bone_prev = _b;
|
|
|
|
return;
|
|
|
|
}
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
var _boneCount = ds_list_size(inputs) - input_fix_len;
|
|
|
|
if(_boneCount != _b.childCount()) setBone();
|
2023-09-14 16:29:39 +02:00
|
|
|
} #endregion
|
2023-06-20 19:43:19 +02:00
|
|
|
|
2023-10-09 16:07:33 +02:00
|
|
|
static update = function(frame = CURRENT_FRAME) { #region
|
2023-10-02 08:57:44 +02:00
|
|
|
var _b = getInputData(0);
|
2023-06-21 20:36:53 +02:00
|
|
|
if(_b == noone) return;
|
|
|
|
|
2023-07-05 15:09:52 +02:00
|
|
|
var _bone_pose = _b.clone();
|
2023-06-26 18:55:41 +02:00
|
|
|
_bone_pose.connect();
|
|
|
|
|
2023-06-23 15:39:24 +02:00
|
|
|
_bone_pose.resetPose();
|
2023-06-21 20:36:53 +02:00
|
|
|
var _bst = ds_stack_create();
|
|
|
|
ds_stack_push(_bst, _bone_pose);
|
|
|
|
|
|
|
|
while(!ds_stack_empty(_bst)) {
|
|
|
|
var bone = ds_stack_pop(_bst);
|
2023-07-05 15:09:52 +02:00
|
|
|
var _id = bone.ID;
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
if(ds_map_exists(boneMap, _id)) {
|
|
|
|
var _inp = boneMap[? _id];
|
2023-09-28 15:10:41 +02:00
|
|
|
_inp.updateName(bone.name);
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
var _trn = _inp.getValue();
|
|
|
|
|
2023-06-23 15:39:24 +02:00
|
|
|
bone.pose_posit = [ _trn[TRANSFORM.pos_x], _trn[TRANSFORM.pos_y] ];
|
|
|
|
bone.pose_angle = _trn[TRANSFORM.rot];
|
|
|
|
bone.pose_scale = _trn[TRANSFORM.sca_x];
|
2023-06-21 20:36:53 +02:00
|
|
|
}
|
|
|
|
|
2023-07-25 20:12:40 +02:00
|
|
|
for( var i = 0, n = array_length(bone.childs); i < n; i++ )
|
2023-06-21 20:36:53 +02:00
|
|
|
ds_stack_push(_bst, bone.childs[i]);
|
|
|
|
}
|
2023-06-20 19:43:19 +02:00
|
|
|
|
2023-06-21 20:36:53 +02:00
|
|
|
ds_stack_destroy(_bst);
|
2023-06-23 15:39:24 +02:00
|
|
|
_bone_pose.setPose();
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
outputs[| 0].setValue(_bone_pose);
|
2023-09-14 16:29:39 +02:00
|
|
|
} #endregion
|
2023-06-20 19:43:19 +02:00
|
|
|
|
2023-09-14 16:29:39 +02:00
|
|
|
static getPreviewBoundingBox = function() { #region
|
2023-07-10 20:14:10 +02:00
|
|
|
var minx = 9999999;
|
|
|
|
var miny = 9999999;
|
|
|
|
var maxx = -9999999;
|
|
|
|
var maxy = -9999999;
|
|
|
|
|
2023-08-01 19:21:51 +02:00
|
|
|
var _b = outputs[| 0].getValue();
|
|
|
|
if(_b == noone) return BBOX().fromPoints(0, 0, 1, 1);
|
|
|
|
|
2023-07-10 20:14:10 +02:00
|
|
|
var _bst = ds_stack_create();
|
|
|
|
ds_stack_push(_bst, _b);
|
|
|
|
|
|
|
|
while(!ds_stack_empty(_bst)) {
|
|
|
|
var __b = ds_stack_pop(_bst);
|
|
|
|
|
2023-07-25 20:12:40 +02:00
|
|
|
for( var i = 0, n = array_length(__b.childs); i < n; i++ ) {
|
2023-07-10 20:14:10 +02:00
|
|
|
var p0 = __b.childs[i].getPoint(0);
|
|
|
|
var p1 = __b.childs[i].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);
|
|
|
|
|
|
|
|
ds_stack_push(_bst, __b.childs[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ds_stack_destroy(_bst);
|
|
|
|
|
|
|
|
if(minx == 9999999) return noone;
|
|
|
|
return BBOX().fromPoints(minx, miny, maxx, maxy);
|
2023-09-14 16:29:39 +02:00
|
|
|
} #endregion
|
2023-07-10 20:14:10 +02:00
|
|
|
|
2023-09-14 16:29:39 +02:00
|
|
|
static doApplyDeserialize = function() { #region
|
2023-06-21 20:36:53 +02:00
|
|
|
for( var i = input_fix_len; i < ds_list_size(inputs); i += data_length ) {
|
|
|
|
var inp = inputs[| i];
|
2023-10-02 08:57:44 +02:00
|
|
|
var idx = struct_try_get(inp.display_data, "bone_id");
|
2023-06-21 20:36:53 +02:00
|
|
|
|
|
|
|
boneMap[? idx] = inp;
|
|
|
|
}
|
2023-06-25 20:12:17 +02:00
|
|
|
|
|
|
|
setBone();
|
2023-09-14 16:29:39 +02:00
|
|
|
} #endregion
|
2023-06-25 20:12:17 +02:00
|
|
|
|
2023-09-14 16:29:39 +02:00
|
|
|
static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) { #region
|
2023-06-25 20:12:17 +02:00
|
|
|
var bbox = drawGetBbox(xx, yy, _s);
|
|
|
|
draw_sprite_fit(s_node_armature_pose, 0, bbox.xc, bbox.yc, bbox.w, bbox.h);
|
2023-09-14 16:29:39 +02:00
|
|
|
} #endregion
|
2023-06-20 19:43:19 +02:00
|
|
|
}
|
|
|
|
|