forked from LeenkxTeam/LNXSDK
165 lines
4.8 KiB
Haxe
165 lines
4.8 KiB
Haxe
package iron.object;
|
|
|
|
#if lnx_morph_target
|
|
|
|
import kha.arrays.Float32Array;
|
|
import kha.Image;
|
|
import kha.FastFloat;
|
|
import iron.data.Data;
|
|
import iron.data.SceneFormat;
|
|
|
|
class MorphTarget {
|
|
|
|
public var data: TMorphTarget;
|
|
public var numMorphTargets: Int = 0;
|
|
public var morphImageSize: Int = 0;
|
|
public var morphBlockSize: Int = 0;
|
|
public var scaling: FastFloat;
|
|
public var offset: FastFloat;
|
|
public var morphWeights: Float32Array;
|
|
public var morphDataPos: Image;
|
|
public var morphDataNor: Image;
|
|
public var morphMap: Map<String, Int> = null;
|
|
|
|
public var isDirty: Bool = true;
|
|
var previousWeights: Float32Array;
|
|
var changeThreshold: FastFloat = 0.001; // skip smaller
|
|
var pendingUpdates: Map<Int, Float> = null;
|
|
var batchUpdateEnabled: Bool = true;
|
|
var lastFlushFrame: Int = 0;
|
|
|
|
public function new(data: TMorphTarget) {
|
|
initWeights(data.morph_target_defaults);
|
|
scaling = data.morph_scale;
|
|
offset = data.morph_offset;
|
|
numMorphTargets = data.num_morph_targets;
|
|
morphImageSize = data.morph_img_size;
|
|
morphBlockSize = data.morph_block_size;
|
|
|
|
Data.getImage(data.morph_target_data_file + "_morph_pos.png", function(img: Image) {
|
|
if (img != null) morphDataPos = img;
|
|
});
|
|
Data.getImage(data.morph_target_data_file + "_morph_nor.png", function(img: Image) {
|
|
if (img != null) morphDataNor = img;
|
|
});
|
|
morphMap = new Map();
|
|
|
|
var i = 0;
|
|
for (name in data.morph_target_ref) {
|
|
morphMap.set(name, i);
|
|
i++;
|
|
}
|
|
|
|
previousWeights = new Float32Array(morphWeights.length);
|
|
for (i in 0...morphWeights.length) {
|
|
previousWeights.set(i, morphWeights.get(i));
|
|
}
|
|
|
|
// batch system
|
|
pendingUpdates = new Map<Int, Float>();
|
|
}
|
|
|
|
inline function initWeights(defaults: Float32Array) {
|
|
morphWeights = new Float32Array(defaults.length);
|
|
for (i in 0...morphWeights.length) {
|
|
morphWeights.set(i, defaults.get(i));
|
|
}
|
|
}
|
|
|
|
public function setMorphValue(name: String, value: Float) {
|
|
var i = morphMap.get(name);
|
|
if (i != null) {
|
|
if (batchUpdateEnabled) {
|
|
pendingUpdates.set(i, value);
|
|
} else {
|
|
setMorphValueDirect(i, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
// faster indexed access
|
|
public inline function setMorphValueDirect(index: Int, value: Float) {
|
|
var current = morphWeights.get(index);
|
|
|
|
// allow explicit zero values to reset
|
|
if (value == 0.0 && current != 0.0) {
|
|
morphWeights.set(index, value);
|
|
isDirty = true;
|
|
return;
|
|
}
|
|
|
|
var delta = value - current;
|
|
|
|
if (delta < -changeThreshold || delta > changeThreshold) {
|
|
morphWeights.set(index, value);
|
|
isDirty = true;
|
|
}
|
|
}
|
|
|
|
// flush pending batch
|
|
public function flushBatchedUpdates() {
|
|
if (pendingUpdates.keys().hasNext()) {
|
|
var anyChanged = false;
|
|
var hasZeros = false;
|
|
|
|
for (index in pendingUpdates.keys()) {
|
|
var value = pendingUpdates.get(index);
|
|
if (value == null) continue;
|
|
|
|
if (value == 0.0) hasZeros = true;
|
|
|
|
var current = morphWeights.get(index);
|
|
var delta = value - current;
|
|
|
|
if (value == 0.0 && current != 0.0) {
|
|
try{
|
|
morphWeights.set(index, cast value);
|
|
}catch(e){
|
|
trace("ERROR: " + e);
|
|
}
|
|
anyChanged = true;
|
|
}
|
|
else if (delta < -changeThreshold || delta > changeThreshold) {
|
|
morphWeights.set(index, cast value);
|
|
anyChanged = true;
|
|
}
|
|
}
|
|
|
|
pendingUpdates.clear();
|
|
|
|
if (anyChanged || hasZeros) {
|
|
isDirty = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
public inline function markClean() {
|
|
isDirty = false;
|
|
for (i in 0...morphWeights.length) {
|
|
previousWeights.set(i, morphWeights.get(i));
|
|
}
|
|
}
|
|
|
|
public inline function markDirty() {
|
|
isDirty = true;
|
|
}
|
|
|
|
// toggle batch mode
|
|
public inline function setBatchMode(enabled: Bool) {
|
|
if (!enabled && batchUpdateEnabled) {
|
|
flushBatchedUpdates();
|
|
}
|
|
batchUpdateEnabled = enabled;
|
|
}
|
|
|
|
public function resetAllWeights() {
|
|
for (i in 0...morphWeights.length) {
|
|
morphWeights.set(i, 0.0);
|
|
}
|
|
pendingUpdates.clear();
|
|
isDirty = true;
|
|
}
|
|
}
|
|
|
|
#end
|