LNXSDK/leenkx/Sources/iron/object/ObjectAnimation.hx
2025-01-22 16:18:30 +01:00

218 lines
6.1 KiB
Haxe

package iron.object;
import iron.object.Animation.ActionSampler;
import kha.arrays.Float32Array;
import kha.FastFloat;
import kha.arrays.Uint32Array;
import iron.math.Vec4;
import iron.math.Mat4;
import iron.math.Quat;
import iron.data.SceneFormat;
class ObjectAnimation extends Animation {
public var object: Object;
public var oactions: Array<TSceneFormat>;
var oaction: TObj;
var s0: FastFloat = 0.0;
var bezierFrameIndex = -1;
var updateAnimation: Map<String, FastFloat> -> Void;
public var transformArr: Float32Array;
public var transformMap: Map<String, FastFloat>;
public static var trackNames: Array<String> = [ "xloc", "yloc", "zloc",
"xrot", "yrot", "zrot",
"qwrot", "qxrot", "qyrot", "qzrot",
"xscl", "yscl", "zscl",
"dxloc", "dyloc", "dzloc",
"dxrot", "dyrot", "dzrot",
"dqwrot", "dqxrot", "dqyrot", "dqzrot",
"dxscl", "dyscl", "dzscl"];
public function new(object: Object, oactions: Array<TSceneFormat>) {
this.object = object;
this.oactions = oactions;
isSkinned = false;
super();
}
function getAction(action: String): TObj {
for (a in oactions) if (a != null && a.objects[0].name == action) return a.objects[0];
return null;
}
override public function play(action = "", onComplete: Void->Void = null, blendTime = 0.0, speed = 1.0, loop = true) {
super.play(action, onComplete, blendTime, speed, loop);
if (this.action == "" && oactions[0] != null) this.action = oactions[0].objects[0].name;
oaction = getAction(this.action);
if (oaction != null) {
isSampled = oaction.sampled != null && oaction.sampled;
}
}
override public function update(delta: FastFloat) {
if (!object.visible || object.culled) return;
#if lnx_debug
Animation.beginProfile();
#end
if(transformMap == null) transformMap = new Map();
transformMap = initTransformMap();
super.update(delta);
if (paused) return;
if(updateAnimation == null) return;
if (!isSkinned) updateObjectAnimation();
#if lnx_debug
Animation.endProfile();
#end
}
public override function getTotalFrames(sampler: ActionSampler): Int {
var track = getAction(sampler.action).anim.tracks[0];
return Std.int(track.frames[track.frames.length - 1] - track.frames[0]);
}
public function initTransformMap(){
var map = new Map<String, Null<FastFloat>>();
for (name in trackNames){
map.set(name, null);
}
return map;
}
public function animationLoop(f: Map<String, FastFloat>->Void){
updateAnimation = f;
}
function updateObjectAnimation() {
updateAnimation(transformMap);
updateTransform(transformMap, object.transform);
object.transform.buildMatrix();
}
override public function updateActionTrack(sampler: ActionSampler) {
if(sampler.paused) return;
if(! sampler.actionDataInit) {
var objanim = getAction(sampler.action);
sampler.setObjectAction(objanim);
}
oaction = sampler.getObjectAction();
updateTrack(oaction.anim, sampler);
}
function updateAnimSampled(anim: TAnimation, transformMap: Map<String, FastFloat>, sampler: ActionSampler) {
for (track in anim.tracks) {
var sign = sampler.speed > 0 ? 1 : -1;
var t = sampler.time;
//t = t < 0 ? 0.1 : t;
var ti = sampler.offset;
//ti = ti < 0 ? 1 : ti;
var t1 = track.frames[ti] * frameTime;
var t2 = track.frames[ti + sign] * frameTime;
var v1 = track.values[ti];
var v2 = track.values[ti + sign];
var value = interpolateLinear(t, t1, t2, v1, v2);
if(value == null) continue;
transformMap.set(track.target, value);
}
}
public function sampleAction(sampler: ActionSampler, transformMap: Map<String, FastFloat>){
if(! sampler.actionDataInit) {
var objanim = getAction(sampler.action);
sampler.setObjectAction(objanim);
}
var objanim = sampler.getObjectAction();
updateAnimSampled(objanim.anim, transformMap, sampler);
}
public function blendActionObject(transformMap1: Map<String, FastFloat>, transformMap2: Map<String, FastFloat>, transformMapRes: Map<String, FastFloat>, factor: FastFloat ) {
for(track in transformMapRes.keys()){
var v1 = transformMap1.get(track);
var v2 = transformMap2.get(track);
if(v1 == null || v2 == null) continue;
var maxVal: FastFloat = 1.0;
var tempValue = (maxVal - factor) * v1 + factor * v2;
transformMapRes.set(track, tempValue);
}
}
inline function interpolateLinear(t: FastFloat, t1: FastFloat, t2: FastFloat, v1: FastFloat, v2: FastFloat): Null<FastFloat> {
var s = (t - t1) / (t2 - t1);
return (1.0 - s) * v1 + s * v2;
}
@:access(iron.object.Transform)
function updateTransform(transformMap: Map<String, FastFloat>, transform: Transform) {
var t = transform;
t.resetDelta();
for (track in transformMap.keys()){
var value = transformMap.get(track);
if(value == null) continue;
switch (track) {
case "xloc": transform.loc.x = value;
case "yloc": transform.loc.y = value;
case "zloc": transform.loc.z = value;
case "xrot": transform.setRotation(value, transform._eulerY, transform._eulerZ);
case "yrot": transform.setRotation(transform._eulerX, value, transform._eulerZ);
case "zrot": transform.setRotation(transform._eulerX, transform._eulerY, value);
case "qwrot": transform.rot.w = value;
case "qxrot": transform.rot.x = value;
case "qyrot": transform.rot.y = value;
case "qzrot": transform.rot.z = value;
case "xscl": transform.scale.x = value;
case "yscl": transform.scale.y = value;
case "zscl": transform.scale.z = value;
// Delta
case "dxloc": transform.dloc.x = value;
case "dyloc": transform.dloc.y = value;
case "dzloc": transform.dloc.z = value;
case "dxrot": transform._deulerX = value;
case "dyrot": transform._deulerY = value;
case "dzrot": transform._deulerZ = value;
case "dqwrot": transform.drot.w = value;
case "dqxrot": transform.drot.x = value;
case "dqyrot": transform.drot.y = value;
case "dqzrot": transform.drot.z = value;
case "dxscl": transform.dscale.x = value;
case "dyscl": transform.dscale.y = value;
case "dzscl": transform.dscale.z = value;
}
}
}
}