Consolidate and update

This commit is contained in:
2026-10-27 15:58:22 -07:00
parent eb211da457
commit 6c13722fc6
42 changed files with 498 additions and 169 deletions

View File

@ -112,6 +112,10 @@ class BoneAnimation extends Animation {
this.data = mo != null ? mo.data : null;
this.isSkinned = data != null ? data.isSkinned : false;
if (this.isSkinned) {
if (armature != null && data.geom.skeletonBoneRefs != null
&& data.geom.actions.keys().hasNext() == false) {
data.geom.addArmature(armature);
}
var boneSize = 12; // Dual-quat skinning + scaling
this.skinBuffer = new Float32Array(skinMaxBones * boneSize);
for (i in 0...this.skinBuffer.length) this.skinBuffer[i] = 0;
@ -205,18 +209,37 @@ class BoneAnimation extends Animation {
}
function setAction(action: String) {
if (armature == null) return;
armature.initMats();
var a = armature.getAction(action);
if (a == null) return;
skeletonBones = a.bones;
skeletonMats = a.mats;
if(! rootMotionCacheInit) skeletonMats.push(Mat4.identity());
if (isSkinned) {
skeletonBones = data.geom.actions.get(action);
var geomMats = data.geom.mats.get(action);
if (geomMats != null) {
skeletonMats = [];
for (i in 0...geomMats.length) {
var m = Mat4.identity();
m.setFrom(geomMats[i]);
skeletonMats.push(m);
}
}
else skeletonMats = null;
}
if (skeletonBones == null) {
if (armature == null) return;
armature.initMats();
var a = armature.getAction(action);
if (a == null) return;
skeletonBones = a.bones;
skeletonMats = a.mats;
}
if (skeletonMats.length == skeletonBones.length) skeletonMats.push(Mat4.identity()); // Root motion cache
rootMotionCacheInit = true;
setMats();
}
function getAction(action: String): Array<TObj> {
if (isSkinned) {
var bones = data.geom.actions.get(action);
if (bones != null) return bones;
}
if (armature == null) return null;
armature.initMats();
var a = armature.getAction(action);
@ -251,15 +274,91 @@ class BoneAnimation extends Animation {
updateAnimation = f;
}
var blendSampler1: ActionSampler = null;
var blendSampler2: ActionSampler = null;
var blendMats: Array<Mat4> = null;
public function blend(action1: String, action2: String, factor: FastFloat) {
var actionName1: String = getName(action1);
var actionName2: String = getName(action2);
if (blendSampler1 == null || blendSampler1.action != actionName1) {
blendSampler1 = new ActionSampler(actionName1);
registerAction("blendSampler1", blendSampler1);
}
if (blendSampler2 == null || blendSampler2.action != actionName2) {
blendSampler2 = new ActionSampler(actionName2);
registerAction("blendSampler2", blendSampler2);
}
blendSampler1.paused = false;
blendSampler2.paused = false;
if (transitionSampler != null) {
transitionSampler.paused = true;
transitionSampler = null;
}
if (currentPlaySampler != null) currentPlaySampler.paused = true;
currentPlaySampler = blendSampler1;
if (skeletonMats == null) setAction(actionName1);
if (skeletonMats == null) return;
if (blendMats == null) blendMats = initMatsEmpty();
updateAnimation = function(mats) {
sampleAction(blendSampler1, mats);
sampleAction(blendSampler2, blendMats);
blendAction(mats, blendMats, mats, factor);
}
}
var playSamplers: Map<String, ActionSampler> = [];
var currentPlaySampler: ActionSampler = null;
var transitionSampler: ActionSampler = null;
var transitionMats: Array<Mat4> = null;
var transitionTime: FastFloat = 0.0;
var transitionDuration: FastFloat = 0.0;
override public function play(action = "", onComplete: Void->Void = null, blendTime = 0.2, speed = 1.0, loop = true) {
var actionName: String = getName(action);
if (actionName != "") {
setAction(actionName);
super.play(actionName, onComplete, blendTime, speed, loop);
var tempAnimParam = new ActionSampler(actionName);
registerAction("tempAction", tempAnimParam);
var sampler = playSamplers.get(actionName);
if (sampler == null) {
if (activeActions != null) sampler = activeActions.get(actionName);
if (sampler == null) sampler = new ActionSampler(actionName);
playSamplers.set(actionName, sampler);
}
if (transitionSampler != null) {
transitionSampler.paused = true;
transitionSampler = null;
}
if (blendTime > 0 && currentPlaySampler != null && currentPlaySampler != sampler && skeletonMats != null) {
transitionSampler = currentPlaySampler;
if (transitionMats == null) transitionMats = initMatsEmpty();
transitionTime = 0.0;
transitionDuration = blendTime;
if (blendSampler1 != null && blendSampler1 != transitionSampler) blendSampler1.paused = true;
if (blendSampler2 != null && blendSampler2 != transitionSampler) blendSampler2.paused = true;
}
else if (currentPlaySampler != null) currentPlaySampler.paused = true;
currentPlaySampler = sampler;
sampler.speed = speed;
sampler.loop = loop;
sampler.onComplete = onComplete != null ? [onComplete] : null;
sampler.restartAction();
registerAction(actionName, sampler);
updateAnimation = function(mats){
sampleAction(tempAnimParam, mats);
if (transitionSampler != null) {
sampleAction(transitionSampler, transitionMats);
sampleAction(sampler, mats);
var f = transitionTime / transitionDuration;
if (f > 1.0) f = 1.0;
f = f * f * (3.0 - 2.0 * f); // Smoothstep
blendAction(transitionMats, mats, mats, f, -1, 0.0);
transitionTime += delta;
if (transitionTime >= transitionDuration) {
transitionSampler.paused = true;
transitionSampler = null;
}
}
else sampleAction(sampler, mats);
}
}
}
@ -279,6 +378,7 @@ class BoneAnimation extends Animation {
#end
super.update(delta);
if (paused) return;
if(updateAnimation != null) {
updateAnimation(skeletonMats);
}
@ -540,12 +640,14 @@ class BoneAnimation extends Animation {
inline function interpolateSample(track: TTrack, m: Mat4, t: FastFloat, ti: Int, sign: Int) {
var tj = ti + sign;
if (tj < 0 || tj >= track.frames.length) tj = ti;
var t1 = track.frames[ti] * frameTime;
var t2 = track.frames[ti + sign] * frameTime;
var s: FastFloat = (t - t1) / (t2 - t1); // Linear
var t2 = track.frames[tj] * frameTime;
var s: FastFloat = t2 != t1 ? (t - t1) / (t2 - t1) : 0.0; // Linear
m1.setF32(track.values, ti * 16); // Offset to 4x4 matrix array
m2.setF32(track.values, (ti + sign) * 16);
m2.setF32(track.values, tj * 16);
// Decompose
m1.decompose(vpos, q1, vscl);
@ -643,7 +745,7 @@ class BoneAnimation extends Animation {
return actionMats != null ? actionMats[getBoneIndex(bone)] : null;
}
function getWorldMat(actionMats: Array<Mat4>, bone: TObj): Mat4 {
public function getWorldMat(actionMats: Array<Mat4>, bone: TObj): Mat4 {
if (applyParent == null) {
applyParent = [];
for (m in actionMats) applyParent.push(true);
@ -728,7 +830,7 @@ class BoneAnimation extends Animation {
// Skip if root motion is disabled
if(j < 0) continue;
// Use Action 2
if(skeletonBones[j].bone_layers[layerMask] || layerMask < 0){
if(layerMask < 0 || skeletonBones[j].bone_layers[layerMask]){
resultMat[i].setFrom(actionMats2[i]);
}
// Use Action 1 if not in layer
@ -744,7 +846,7 @@ class BoneAnimation extends Animation {
// Skip if root motion is disabled
if(j < 0) continue;
// Blend
if(skeletonBones[j].bone_layers[j] || layerMask < 0) {
if(layerMask < 0 || skeletonBones[j].bone_layers[layerMask]) {
// Decompose
m.setFrom(actionMats1[i]);
m1.setFrom(actionMats2[i]);
@ -786,8 +888,10 @@ class BoneAnimation extends Animation {
}
else{
for(i in 0...baseActionMats.length){
var j = i == skeletonBones.length ? rootMotionIndex : i;
if(j < 0) continue;
if(skeletonBones[i].bone_layers[layerMask] || layerMask < 0) {
if(layerMask < 0 || skeletonBones[j].bone_layers[layerMask]) {
// Decompose
m.setFrom(baseActionMats[i]);
m1.setFrom(addActionMats[i]);