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

@ -34,7 +34,6 @@ import iron.math.Quat;
class RenderPath {
public static var active: RenderPath;
#if lnx_vr
static var vrSimulateMode: Bool = false;
static var vrCameraOffsetSet:Bool = false;
static var vrCameraOffset:Vec4 = new Vec4();
static var wasVRPresenting:Bool = false;
@ -45,6 +44,9 @@ class RenderPath {
public static var vrCenterCameraWorld:Mat4 = null;
static var vrOriginalSuperSample:Float = -1.0;
#end
static var vrSimulateMode: Bool = false;
public static inline function isVRPresenting(): Bool {
#if (kha_webgl && lnx_vr)
return kha.vr.VrInterface.instance != null && kha.vr.VrInterface.instance.IsPresenting();
@ -57,8 +59,6 @@ class RenderPath {
return vrSimulateMode;
}
#end
public var frameScissor = false;
public var frameScissorX = 0;
public var frameScissorY = 0;

View File

@ -1003,7 +1003,7 @@ class Scene {
}
if (o.vertex_groups != null) {
cast(object, MeshObject).vertexGroups = new Map();
object.vertexGroups = new Map();
for (p in o.vertex_groups) {
var verts:Array<iron.math.Vec4> = [];
@ -1014,7 +1014,7 @@ class Scene {
verts.push(new iron.math.Vec4(data[i * 3], data[i * 3 + 1], data[i * 3 + 2], 1.0));
}
}
cast(object, MeshObject).vertexGroups.set(p.name, verts);
object.vertexGroups.set(p.name, verts);
}
}

View File

@ -58,6 +58,7 @@ class Geometry {
// Skinned
#if lnx_skin
public var skeletonTransformsI: Array<Mat4> = null;
public var skeletonBoneRefs: Array<String> = null;
public var actions: Map<String, Array<iron.data.SceneFormat.TObj>> = new Map();
public var mats: Map<String, Array<Mat4>> = new Map();
#end
@ -326,6 +327,33 @@ class Geometry {
// Skinned
#if lnx_skin
public function addArmature(armature: iron.data.Armature) {
for (a in armature.actions) {
addAction(a.bones, a.name);
}
}
public function addAction(bones: Array<TObj>, name: String) {
if (bones == null || skeletonBoneRefs == null) return;
if (actions.get(name) != null) return;
var actionBones: Array<TObj> = [];
for (s in skeletonBoneRefs) {
for (b in bones) {
if (b.name == s) {
actionBones.push(b);
}
}
}
actions.set(name, actionBones);
var actionMats: Array<Mat4> = [];
for (b in actionBones) {
actionMats.push(Mat4.fromFloat32Array(b.transform.values));
}
mats.set(name, actionMats);
}
public function initSkeletonTransforms(transformsI: Array<Float32Array>) {
skeletonTransformsI = [];
for (t in transformsI) {

View File

@ -108,6 +108,7 @@ class MeshData {
// Skinned
#if lnx_skin
if (raw.skin != null) {
dat.geom.skeletonBoneRefs = raw.skin.bone_ref_array;
dat.geom.initSkeletonTransforms(raw.skin.transformsI);
}
#end

View File

@ -49,7 +49,7 @@ class Reader {
* @see https://msdn.microsoft.com/en-us/library/windows/desktop/dd318229(v=vs.85).aspx
* @see https://en.wikipedia.org/wiki/BMP_file_format#Bitmap_file_header
*/
public function read() : format.bmp.Data {
public function read() : iron.format.bmp.Data {
// Read Header
for (b in ["B".code, "M".code]) {
if (input.readByte() != b) throw "Invalid header";

View File

@ -1,5 +1,5 @@
package format.gif;
import format.gif.Data;
package iron.format.gif;
import iron.format.gif.Data;
import haxe.ds.Vector;
import haxe.io.Bytes;
import haxe.io.Output;

View File

@ -29,7 +29,7 @@
*/
package iron.format.jpg;
class Writer {
class WriterOriginal {
var ZigZag: Array<Int>;
// Static table initialization

View File

@ -40,11 +40,6 @@ class Animation {
public var paused = false;
var frameTime: FastFloat = 1 / 60;
var blendTime: FastFloat = 0.0;
var blendCurrent: FastFloat = 0.0;
var blendFactor: FastFloat = 0.0;
var lastFrameIndex = -1;
var markerEvents: Map<ActionSampler, Map<String, Array<Void->Void>>> = null;
public var activeActions: Map<String, ActionSampler> = null;
@ -63,8 +58,6 @@ class Animation {
public function play(action = "", onComplete: Void->Void = null, blendTime = 0.0, speed = 1.0, loop = true) {
if (blendTime > 0) {
this.blendTime = blendTime;
this.blendCurrent = 0.0;
frameIndex = 0;
time = 0.0;
}
@ -93,6 +86,7 @@ class Animation {
}
public function update(delta: FastFloat) {
if (paused) return;
if(activeActions == null) return;
for(sampler in activeActions){
@ -160,24 +154,25 @@ class Animation {
while (checkFrameIndex(track.frames, time, frameIndex, speed)) frameIndex += sign;
// Marker events
if (markerEvents != null && anim.marker_names != null && frameIndex != lastFrameIndex) {
if(markerEvents.get(sampler) != null){
if (markerEvents != null && anim.marker_names != null && frameIndex != sampler.offsetOld) {
var markerListeners = markerEvents.get(sampler);
if (markerListeners != null) {
var fromFrame = sampler.offsetOld < 0 ?
(speed > 0 ? -1 : track.frames[track.frames.length - 1] + 1) :
track.frames[sampler.offsetOld];
var toFrame = track.frames[frameIndex];
for (i in 0...anim.marker_frames.length) {
if (frameIndex == anim.marker_frames[i]) {
var markerAct = markerEvents.get(sampler);
var ar = markerAct.get(anim.marker_names[i]);
if (ar != null) for (f in ar) f();
} else {
for (j in 0...(frameIndex - lastFrameIndex)) {
if (lastFrameIndex + j + 1 == anim.marker_frames[i]) {
var markerAct = markerEvents.get(sampler);
var ar = markerAct.get(anim.marker_names[i]);
if (ar != null) for (f in ar) f();
}
}
var markerFrame = anim.marker_frames[i];
var crossed =
(speed > 0 && toFrame >= fromFrame && markerFrame > fromFrame && markerFrame <= toFrame) ||
(speed < 0 && toFrame <= fromFrame && markerFrame <= fromFrame && markerFrame > toFrame) ||
(speed > 0 && toFrame < fromFrame && (markerFrame > fromFrame || markerFrame <= toFrame)) ||
(speed < 0 && toFrame > fromFrame && (markerFrame >= toFrame || markerFrame < fromFrame));
if (crossed) {
var listeners = markerListeners.get(anim.marker_names[i]);
if (listeners != null) for (listener in listeners) listener();
}
}
lastFrameIndex = frameIndex;
}
}
@ -191,8 +186,8 @@ class Animation {
else {
frameIndex -= sign;
sampler.paused = true;
if (sampler.onComplete != null) for(func in sampler.onComplete){ func();};
}
if (sampler.onComplete != null) for(func in sampler.onComplete){ func();};
sampler.trackEnd = true;
}

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]);

View File

@ -13,7 +13,10 @@ class Constraint {
}
public function apply(transform: Transform) {
if (target == null && raw.target != null) target = Scene.active.getChild(raw.target).transform;
if (target == null && raw.target != null) {
var o = Scene.active.getChild(raw.target);
if (o != null) target = o.transform;
}
if (target == null && raw.type != "LIMIT_LOCATION" && raw.type != "LIMIT_ROTATION" && raw.type != "LIMIT_SCALE") return;

View File

@ -48,7 +48,6 @@ class MeshObject extends Object {
#if lnx_morph_target
public var morphTarget: MorphTarget = null;
#end
public var vertexGroups: Map<String, Array<Vec4>> = null;
#if lnx_veloc
public var prevMatrix = Mat4.identity();
@ -240,6 +239,7 @@ class MeshObject extends Object {
return setCulled(isShadow, true);
}
#if rp_shadowmap
if (isShadow && light.data.raw.type == "sun") {
var frame = RenderPath.active.frame;
if (shadowCameraCullFrame == frame && shadowCameraCullCamera == camera &&
@ -270,10 +270,8 @@ class MeshObject extends Object {
}
}
}
#end
}
//culled = false;
//return culled;
return setCulled(isShadow, false);
}

View File

@ -15,6 +15,7 @@ class Object {
public var transform: Transform;
public var constraints: Array<Constraint> = null;
public var traits: Array<Trait> = [];
public var vertexGroups: Map<String, Array<iron.math.Vec4>> = null;
public var parent: Object = null;
public var children: Array<Object> = [];

View File

@ -17,6 +17,7 @@ class ObjectAnimation extends Animation {
public var oactions: Array<TSceneFormat>;
var oaction: TObj;
var s0: FastFloat = 0.0;
var delta: FastFloat = 0;
var bezierFrameIndex = -1;
var updateAnimation: Map<String, FastFloat> -> Void;
@ -26,7 +27,11 @@ class ObjectAnimation extends Animation {
public var transformMap: Map<String, FastFloat>;
var defaultSampler: ActionSampler = null;
static inline var DEFAULT_SAMPLER_ID = "__object_default_action__";
var playSamplers: Map<String, ActionSampler> = [];
var transitionSampler: ActionSampler = null;
var transitionMap: Map<String, FastFloat> = null;
var transitionTime: FastFloat = 0.0;
var transitionDuration: FastFloat = 0.0;
public static var trackNames: Array<String> = [ "xloc", "yloc", "zloc",
"xrot", "yrot", "zrot",
@ -67,27 +72,59 @@ class ObjectAnimation extends Animation {
oaction = getAction(this.action);
if (oaction != null) {
isSampled = oaction.sampled != null && oaction.sampled;
if (defaultSampler != null) {
deRegisterAction(DEFAULT_SAMPLER_ID);
var sampler = playSamplers.get(this.action);
if (sampler == null) {
if (activeActions != null) sampler = activeActions.get(this.action);
if (sampler == null) sampler = new ActionSampler(this.action);
playSamplers.set(this.action, sampler);
}
var callbacks = onComplete != null ? [onComplete] : null;
defaultSampler = new ActionSampler(this.action, speed, loop, false, callbacks);
registerAction(DEFAULT_SAMPLER_ID, defaultSampler);
if (paused) defaultSampler.paused = true;
if (transitionSampler != null) {
transitionSampler.paused = true;
transitionSampler = null;
}
if (blendTime > 0 && defaultSampler != null && defaultSampler != sampler) {
transitionSampler = defaultSampler;
transitionMap = initTransformMap();
transitionTime = 0.0;
transitionDuration = blendTime;
}
else if (defaultSampler != null) defaultSampler.paused = true;
defaultSampler = sampler;
sampler.speed = speed;
sampler.loop = loop;
sampler.onComplete = onComplete != null ? [onComplete] : null;
sampler.restartAction();
registerAction(this.action, sampler);
updateAnimation = function(map: Map<String, FastFloat>) {
sampleAction(defaultSampler, map);
if (transitionSampler != null) {
sampleAction(transitionSampler, transitionMap);
sampleAction(sampler, map);
var f = transitionTime / transitionDuration;
if (f > 1.0) f = 1.0;
f = f * f * (3.0 - 2.0 * f); // Smoothstep
blendActionObject(transitionMap, map, map, f);
transitionTime += delta;
if (transitionTime >= transitionDuration) {
transitionSampler.paused = true;
transitionSampler = null;
}
}
else sampleAction(sampler, map);
};
}
else {
if (defaultSampler != null) {
deRegisterAction(DEFAULT_SAMPLER_ID);
defaultSampler = null;
if (transitionSampler != null) {
transitionSampler.paused = true;
transitionSampler = null;
}
if (defaultSampler != null) defaultSampler.paused = true;
defaultSampler = null;
updateAnimation = null;
}
}
override public function update(delta: FastFloat) {
this.delta = delta;
if (!object.visible || object.culled) return;
#if lnx_debug
@ -98,7 +135,6 @@ class ObjectAnimation extends Animation {
transformMap = initTransformMap();
super.update(delta);
if (defaultSampler != null) defaultSampler.paused = paused;
if (paused) return;
if (updateAnimation == null) return;
if (!isSkinned) updateObjectAnimation();
@ -160,11 +196,13 @@ class ObjectAnimation extends Animation {
var ti = sampler.offset;
//ti = ti < 0 ? 1 : ti;
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 t2 = track.frames[tj] * frameTime;
var v1 = track.values[ti];
var v2 = track.values[ti + sign];
var v2 = track.values[tj];
var value = interpolateLinear(t, t1, t2, v1, v2);
@ -202,6 +240,7 @@ class ObjectAnimation extends Animation {
}
inline function interpolateLinear(t: FastFloat, t1: FastFloat, t2: FastFloat, v1: FastFloat, v2: FastFloat): Null<FastFloat> {
if (t2 == t1) return v1;
var s = (t - t1) / (t2 - t1);
return (1.0 - s) * v1 + s * v2;
}

View File

@ -131,13 +131,20 @@ class Transform {
dscale = new Vec4().set(1, 1, 1);
}
static var _cdLoc = new Vec4();
static var _cdRot = new Quat();
static var _cdScale = new Vec4();
function composeDelta() {
// Delta transform
dloc.addvecs(loc, dloc);
dscale.addvecs(dscale, scale);
drot.fromEuler(_deulerX, _deulerY, _deulerZ);
drot.multquats(rot, drot);
local.compose(dloc, drot, dscale);
// Delta transform: additive location, multiplicative rotation and scale
_cdLoc.addvecs(loc, dloc);
_cdScale.x = scale.x * dscale.x;
_cdScale.y = scale.y * dscale.y;
_cdScale.z = scale.z * dscale.z;
_cdRot.fromEuler(_deulerX, _deulerY, _deulerZ);
_cdRot.multquats(_cdRot, drot);
_cdRot.multquats(rot, _cdRot);
local.compose(_cdLoc, _cdRot, _cdScale);
}
/**

View File

@ -38,14 +38,14 @@ class Time {
static var normalModeLogged: Bool = false;
#end
static var lastTime = 0.0;
static var lastTime = -1.0;
static var _delta = 0.0;
public static var delta(get, never): Float;
static function get_delta(): Float {
return _delta;
}
static var lastRenderTime = 0.0;
static var lastRenderTime = -1.0;
static var _renderDelta = 0.0;
public static var renderDelta(get, never): Float;
static function get_renderDelta(): Float {
@ -79,12 +79,14 @@ class Time {
}
#end
_delta = realTime() - lastTime;
lastTime = realTime();
var now = realTime();
_delta = lastTime < 0.0 ? 0.0 : now - lastTime;
lastTime = now;
}
public static function render() {
_renderDelta = realTime() - lastRenderTime;
lastRenderTime = realTime();
var now = realTime();
_renderDelta = lastRenderTime < 0.0 ? 0.0 : now - lastRenderTime;
lastRenderTime = now;
}
}

View File

@ -35,13 +35,13 @@ class AnimActionNode extends LogicNode {
if(object.animation == null) {
#if lnx_skin
animationBone = object.getBoneAnimation(object.uid);
animationBone.registerAction(property0, sampler);
animationBone.registerAction(sampler.action, sampler);
func = sampleBonaAction;
#end
}
else{
animationObject = cast(object.animation, ObjectAnimation);
animationObject.registerAction(property0, sampler);
animationObject.registerAction(sampler.action, sampler);
func = sampleObjectAction;
}

View File

@ -61,14 +61,16 @@ class BlendActionNode extends LogicNode {
return;
}
if(factor > 0.95) {
inputs[2].get()(animMats);
var action2 = inputs[2].get();
if (action2 != null) action2(animMats); else inputs[1].get()(animMats);
return;
}
}
inputs[1].get()(animMats);
inputs[2].get()(tempMats);
var action2 = inputs[2].get();
if (action2 == null) return;
action2(tempMats);
animationBone.blendAction(animMats, tempMats, animMats, factor, boneLayer);
}

View File

@ -7,6 +7,9 @@ class OnActionMarkerNode extends LogicNode {
public var property0: String;
public var property1: String;
var registeredSamplers: Array<iron.object.Animation.ActionSampler> = [];
var registeredCallbacks: Map<iron.object.Animation.ActionSampler, Void->Void> = new Map();
public function new(tree: LogicTree) {
super(tree);
@ -21,9 +24,33 @@ class OnActionMarkerNode extends LogicNode {
assert(Error, object != null, "Object input cannot be null");
var animation = object.animation;
if (animation == null) animation = object.getBoneAnimation(object.uid);
var action = animation.activeActions.get(actionID);
if(action == null) return;
animation.notifyOnMarker(action, marker, function() { runOutput(0); });
tree.removeUpdate(init);
if (animation == null) return;
var active = animation.activeActions;
if (active == null) return;
var i = registeredSamplers.length;
while (i-- > 0) {
var alive = false;
for (sampler in active) if (sampler == registeredSamplers[i]) {
alive = true;
break;
}
if (!alive) {
var s = registeredSamplers[i];
animation.removeMarker(s, marker, registeredCallbacks.get(s));
registeredCallbacks.remove(s);
registeredSamplers.splice(i, 1);
}
}
for (key in active.keys()) {
var sampler = active.get(key);
if (actionID != "" && key != actionID && sampler.action != actionID) continue;
if (registeredSamplers.indexOf(sampler) != -1) continue;
registeredSamplers.push(sampler);
var cb = function() { runOutput(0); };
registeredCallbacks.set(sampler, cb);
animation.notifyOnMarker(sampler, marker, cb);
}
}
}

View File

@ -27,11 +27,11 @@ class PlayAnimationTreeNode extends LogicNode {
}
function playAnim() {
if (init = false) return;
if (init == false) return;
init = false;
tree.removeUpdate(playAnim);
var animation = object.animation;
if(animation == null) {
#if lnx_skin

View File

@ -16,8 +16,10 @@ class RestartActionNode extends LogicNode {
var animation = object.animation;
if (animation == null) animation = object.getBoneAnimation(object.uid);
if(animation.activeActions == null) return;
animation.activeActions.get(action).restartAction();
if (animation == null || animation.activeActions == null) return;
var sampler = animation.activeActions.get(action);
if (sampler == null) return;
sampler.restartAction();
runOutput(0);
}

View File

@ -19,8 +19,10 @@ class SetActionPausedNode extends LogicNode {
var animation = object.animation;
if (animation == null) animation = object.getBoneAnimation(object.uid);
if(animation.activeActions == null) return;
animation.activeActions.get(action).paused = paused;
if (animation == null || animation.activeActions == null) return;
var sampler = animation.activeActions.get(action);
if (sampler == null) return;
sampler.paused = paused;
runOutput(0);
}

View File

@ -1,4 +1,4 @@
// Reference: https://github.com/leenkx3d/leenkx_docs/blob/master/dev/renderpath.md
// Reference: https://dev.leenkx.com/LeenkxTeam/LNXSDK/src/branch/main/api/src/manual/renderpath.md
package leenkx.renderpath;
import iron.RenderPath;

View File

@ -222,7 +222,7 @@ class RenderPathForward {
}
#end
#if ((rp_antialiasing == "SMAA") || (rp_antialiasing == "TAA") || (rp_ssr && !rp_ssr_half) || (rp_water) || (rp_depth_texture))
#if ((rp_antialiasing == "SMAA") || (rp_antialiasing == "TAA") || (rp_fsr1 && rp_supersampling != 4) || (rp_ssr && !rp_ssr_half) || (rp_water) || (rp_depth_texture))
{
var t = new RenderTargetRaw();
t.name = "bufa";

View File

@ -139,10 +139,10 @@ class NavAgent extends Trait {
if (forward.length() > 0.0001) {
forward.normalize();
var xAxis = new Vec4(1, 0, 0, 0);
xAxis.applyQuat(targetRot);
var yAxis = new Vec4(0, -1, 0, 0);
yAxis.applyQuat(targetRot);
var currForward = new Vec4().setFrom(xAxis);
var currForward = new Vec4().setFrom(yAxis);
var twist = new Quat().fromTo(currForward, forward);

View File

@ -263,8 +263,6 @@ class VehicleWheel {
}
}
#end
#elseif lnx_jolt
typedef VehicleBody = leenkx.trait.physics.jolt.VehicleBody;

View File

@ -4,41 +4,84 @@ package leenkx.trait.internal;
class LoadingScreen {
public static var bgImageName = 'splash.png';
public static var barColor: kha.Color = 0xff2ae0e0;
public static var bgColor: kha.Color = 0xff002a35;
public static var imageFit = 'Center';
public static var showPercentage = true;
static var font: kha.Font = null;
static var fontRequested: Bool = false;
static var randomColorR: Float = 0;
static var randomColorG: Float = 0;
static var randomColorB: Float = 0;
static var isInitialized = false;
static var bgImage: kha.Image = null;
static var bgRequested: Bool = false;
public static function render(g: kha.graphics2.Graphics, assetsLoaded: Int, assetsTotal: Int) {
if (!isInitialized) {
randomColorR = Math.random();
randomColorG = Math.random();
randomColorB = Math.random();
isInitialized = true;
}
var progress = assetsLoaded / assetsTotal;
var r = progress * randomColorR;
var gg = progress * randomColorG;
var b = progress * randomColorB;
final barHeight = 18;
var w = iron.App.w();
var h = iron.App.h();
g.color = kha.Color.fromFloats(r, gg, b, 1);
g.fillRect(0, iron.App.h() - 50, iron.App.w() / assetsTotal * assetsLoaded, 50);
g.color = bgColor;
g.fillRect(0, 0, w, h);
if (font == null && !fontRequested) {
fontRequested = true;
iron.data.Data.getFont('font_default.ttf', (f: kha.Font) -> {
font = f;
if (bgImageName != '' && bgImage == null && !bgRequested) {
bgRequested = true;
iron.data.Data.getImage(bgImageName, (i: kha.Image) -> {
bgImage = i;
});
}
else if (font != null) {
g.font = font;
g.fontSize = 50;
if (bgImage != null) {
g.color = 0xffffffff;
g.drawString(Math.floor(progress * 100) + '%', iron.App.w() / assetsTotal * assetsLoaded - 80, iron.App.h() - 50);
if (imageFit == 'Stretch') {
g.drawScaledImage(bgImage, 0, 0, w, h);
}
else {
var anchor = imageFit;
var dw: Float = bgImage.width;
var dh: Float = bgImage.height;
if (anchor.indexOf('Contain') == 0) {
var scale = Math.min(w / dw, h / dh);
dw *= scale;
dh *= scale;
anchor = anchor.length > 7 ? anchor.substr(7) : 'Center';
}
var x = 0.0;
var y = 0.0;
switch (anchor) {
case 'TopCenter' | 'Center' | 'BottomCenter':
x = (w - dw) / 2;
case 'TopRight' | 'CenterRight' | 'BottomRight':
x = w - dw;
default:
}
switch (anchor) {
case 'CenterLeft' | 'Center' | 'CenterRight':
y = (h - dh) / 2;
case 'BottomLeft' | 'BottomCenter' | 'BottomRight':
y = h - dh;
default:
}
g.drawScaledImage(bgImage, x, y, dw, dh);
}
}
g.color = barColor;
g.fillRect(0, h - barHeight, w / assetsTotal * assetsLoaded, barHeight);
if (showPercentage) {
if (font == null && !fontRequested) {
fontRequested = true;
iron.data.Data.getFont('font_default.ttf', (f: kha.Font) -> {
font = f;
});
}
else if (font != null) {
g.font = font;
g.fontSize = 30;
g.color = barColor;
g.drawString(Math.floor(progress * 100) + '%', w / assetsTotal * assetsLoaded - 60, h - barHeight - 34);
}
}
}
}