Pixel-Composer/scripts/node_armature_pose/node_armature_pose.gml
2024-11-26 17:28:04 +07:00

310 lines
8.2 KiB
Text

function Node_Armature_Pose(_x, _y, _group = noone) : Node(_x, _y, _group) constructor {
name = "Armature Pose";
setDimension(96, 72);
newInput(0, nodeValue_Armature("Armature", self, noone))
.setVisible(true, true);
input_display_list = [ 0,
["Bones", false]
]
newOutput(0, nodeValue_Output("Armature", self, VALUE_TYPE.armature, noone));
boneMap = {};
attributes.display_name = true;
attributes.display_bone = 0;
array_push(attributeEditors, "Display");
array_push(attributeEditors, ["Display name", function() /*=>*/ {return attributes.display_name}, new checkBox(function() /*=>*/ { attributes.display_name = !attributes.display_name; })]);
array_push(attributeEditors, ["Display bone", function() /*=>*/ {return attributes.display_bone}, new scrollBox(["Octahedral", "Stick"], function(ind) /*=>*/ { attributes.display_bone = ind; })]);
static createNewInput = function(bone = noone) {
var index = array_length(inputs);
newInput(index, nodeValue(bone != noone? bone.name : "bone", self, CONNECT_TYPE.input, VALUE_TYPE.float, [ 0, 0, 0, 1 ] ))
.setDisplay(VALUE_DISPLAY.transform);
inputs[index].attributes.bone_id = bone != noone? bone.ID : noone;
if(bone != noone) boneMap[$ bone.ID] = inputs[index];
array_push(input_display_list, index);
return inputs[index];
}
setDynamicInput(1, false);
static setBone = function() {
//print("Setting dem bones...");
var _b = getInputData(0);
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);
for( var i = 0, n = array_length(__b.childs); i < n; i++ ) {
array_push(_bones, __b.childs[i]);
ds_stack_push(_bst, __b.childs[i]);
}
}
ds_stack_destroy(_bst);
var _inputs = [ inputs[0] ];
var _input_display_list = [
input_display_list[0],
input_display_list[1]
];
for( var i = 0, n = array_length(_bones); i < n; i++ ) {
var bone = _bones[i];
var _idx = array_length(_inputs);
var _inp;
array_push(_input_display_list, _idx);
if(struct_exists(boneMap, bone.ID)) {
_inp = boneMap[$ bone.ID];
_inp.index = _idx;
array_push(_inputs, _inp);
} else
_inp = createNewInput(bone);
array_push(_inputs, _inp);
}
inputs = _inputs;
input_display_list = _input_display_list;
}
tools = [];
anchor_selecting = noone;
posing_bone = noone;
posing_input = 0;
posing_type = 0;
posing_sx = 0;
posing_sy = 0;
posing_sz = 0;
posing_mx = 0;
posing_my = 0;
static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) {
var _b = outputs[0].getValue();
if(_b == noone) return;
anchor_selecting = _b.draw(attributes, active * 0b111, _x, _y, _s, _mx, _my, anchor_selecting, posing_bone);
var mx = (_mx - _x) / _s;
var my = (_my - _y) / _s;
var smx = value_snap(mx, _snx);
var smy = value_snap(my, _sny);
if(posing_bone) {
if(posing_type == 0 && posing_bone.parent) { //move
var ang = posing_bone.parent.pose_angle;
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];
var val = array_clone(posing_input.getValue());
val[TRANSFORM.pos_x] = bx;
val[TRANSFORM.pos_y] = by;
if(posing_input.setValue(val))
UNDO_HOLDING = true;
} else if(posing_type == 1) { //scale
var ss = point_distance(posing_mx, posing_my, smx, smy) / posing_sx;
var ori = posing_bone.getHead();
var ang = point_direction(ori.x, ori.y, smx, smy);
var rot = ang - posing_sy - posing_bone.parent.pose_angle;
var val = array_clone(posing_input.getValue());
val[TRANSFORM.sca_x] = ss;
val[TRANSFORM.rot] = rot;
if(posing_input.setValue(val))
UNDO_HOLDING = true;
} else if(posing_type == 2) { //rotate
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_sx += rot;
var val = array_clone(posing_input.getValue());
val[TRANSFORM.rot] = posing_sx;
if(posing_input.setValue(val))
UNDO_HOLDING = true;
}
if(mouse_release(mb_left)) {
posing_bone = noone;
posing_type = noone;
UNDO_HOLDING = false;
}
}
if(anchor_selecting != noone && mouse_press(mb_left, active)) {
posing_bone = anchor_selecting[0];
if(!struct_exists(boneMap, posing_bone.ID)) setBone();
posing_input = boneMap[$ posing_bone.ID];
if(anchor_selecting[1] == 0 || anchor_selecting[0].IKlength) { // move
posing_type = 0;
var val = posing_input.getValue();
posing_sx = val[TRANSFORM.pos_x];
posing_sy = val[TRANSFORM.pos_y];
var _p = anchor_selecting[2];
posing_mx = _p.x;
posing_my = _p.y;
} else if(anchor_selecting[1] == 1) { // scale
posing_type = 1;
var ori = posing_bone.getHead();
var val = posing_input.getValue();
posing_sx = posing_bone.length / posing_bone.pose_scale * posing_bone.parent.pose_scale;
posing_sy = posing_bone.angle - posing_bone.pose_local_angle;
posing_sz = point_direction(ori.x, ori.y, smx, smy);
var pnt = posing_bone.getHead();
posing_mx = pnt.x;
posing_my = pnt.y;
} else if(anchor_selecting[1] == 2) { // rotate
posing_type = 2;
var ori = posing_bone.getHead();
var val = posing_input.getValue();
posing_sx = val[TRANSFORM.rot];
posing_sy = point_direction(ori.x, ori.y, mx, my);
posing_mx = mx;
posing_my = my;
}
}
}
bone_prev = noone;
static step = function() {
var _b = getInputData(0);
if(_b == noone) return;
if(bone_prev != _b) {
setBone();
bone_prev = _b;
return;
}
var _boneCount = array_length(inputs) - input_fix_len;
if(_boneCount != _b.childCount()) setBone();
}
static update = function(frame = CURRENT_FRAME) {
var _b = getInputData(0);
if(_b == noone) return;
var _bone_pose = _b.clone();
_bone_pose.connect();
_bone_pose.resetPose();
var _bst = ds_stack_create();
ds_stack_push(_bst, _bone_pose);
while(!ds_stack_empty(_bst)) {
var bone = ds_stack_pop(_bst);
var _id = bone.ID;
if(struct_exists(boneMap, _id)) {
var _inp = boneMap[$ _id];
_inp.updateName(bone.name);
var _trn = _inp.getValue();
bone.pose_posit = [ _trn[TRANSFORM.pos_x], _trn[TRANSFORM.pos_y] ];
bone.pose_angle = _trn[TRANSFORM.rot];
bone.pose_scale = _trn[TRANSFORM.sca_x];
}
for( var i = 0, n = array_length(bone.childs); i < n; i++ )
ds_stack_push(_bst, bone.childs[i]);
}
ds_stack_destroy(_bst);
_bone_pose.setPose();
outputs[0].setValue(_bone_pose);
}
static getPreviewBoundingBox = function() {
var minx = 9999999;
var miny = 9999999;
var maxx = -9999999;
var maxy = -9999999;
var _b = outputs[0].getValue();
if(_b == noone) return BBOX().fromPoints(0, 0, 1, 1);
var _bst = ds_stack_create();
ds_stack_push(_bst, _b);
while(!ds_stack_empty(_bst)) {
var __b = ds_stack_pop(_bst);
for( var i = 0, n = array_length(__b.childs); i < n; i++ ) {
var p0 = __b.childs[i].getHead();
var p1 = __b.childs[i].getTail();
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);
}
static postApplyDeserialize = function() {
for( var i = input_fix_len; i < array_length(inputs); i += data_length ) {
var inp = inputs[i];
var idx = LOADING_VERSION < 1_18_04_0? struct_try_get(inp.display_data, "bone_id", 0) :
struct_try_get(inp.attributes, "bone_id", 0);
boneMap[$ idx] = inp;
inp.attributes.bone_id = idx;
}
setBone();
}
static onDrawNode = function(xx, yy, _mx, _my, _s, _hover, _focus) {
var bbox = drawGetBbox(xx, yy, _s);
draw_sprite_fit(s_node_armature_pose, 0, bbox.xc, bbox.yc, bbox.w, bbox.h);
}
}