LNXSDK/leenkx/Sources/iron/data/MeshData.hx

130 lines
3.4 KiB
Haxe
Raw Normal View History

2025-01-22 16:18:30 +01:00
package iron.data;
import kha.graphics4.Usage;
import kha.graphics4.VertexData;
import kha.arrays.Int16Array;
import kha.arrays.Uint32Array;
import iron.data.SceneFormat;
class MeshData {
public var name: String;
public var raw: TMeshData;
public var format: TSceneFormat;
public var geom: Geometry;
public var start = 0; // Batched
public var count = -1;
public var refcount = 0; // Number of users
public var handle: String; // Handle used to retrieve this object in Data
public var scalePos: kha.FastFloat = 1.0;
public var scaleTex: kha.FastFloat = 1.0;
public var isSkinned: Bool;
public function new(raw: TMeshData, done: MeshData->Void) {
this.raw = raw;
this.name = raw.name;
if (raw.scale_pos != null) scalePos = raw.scale_pos;
if (raw.scale_tex != null) scaleTex = raw.scale_tex;
// Mesh data
var indices: Array<Uint32Array> = [];
var materialIndices: Array<Int> = [];
for (ind in raw.index_arrays) {
indices.push(ind.values);
materialIndices.push(ind.material);
}
// Skinning
isSkinned = raw.skin != null;
// Prepare vertex array for skinning and fill size data
var vertexArrays = raw.vertex_arrays;
if (isSkinned) {
vertexArrays.push({ attrib: "bone", values: null, data: "short4norm" });
vertexArrays.push({ attrib: "weight", values: null, data: "short4norm" });
}
for (i in 0...vertexArrays.length) {
vertexArrays[i].size = getVertexSize(vertexArrays[i].data, getPadding(vertexArrays[i].padding));
}
// Usage, also used for instanced data
var parsedUsage = Usage.StaticUsage;
if (raw.dynamic_usage != null && raw.dynamic_usage == true) parsedUsage = Usage.DynamicUsage;
var usage = parsedUsage;
if (isSkinned) {
var bonea = null;
var weighta = null;
var vertex_length = Std.int(vertexArrays[0].values.length / vertexArrays[0].size);
var l = vertex_length * 4;
bonea = new Int16Array(l);
weighta = new Int16Array(l);
var index = 0;
var ai = 0;
for (i in 0...vertex_length) {
var boneCount = raw.skin.bone_count_array[i];
for (j in index...(index + boneCount)) {
bonea[ai] = raw.skin.bone_index_array[j];
weighta[ai] = raw.skin.bone_weight_array[j];
ai++;
}
// Fill unused weights
for (j in boneCount...4) {
bonea[ai] = 0;
weighta[ai] = 0;
ai++;
}
index += boneCount;
}
vertexArrays[vertexArrays.length - 2].values = bonea;
vertexArrays[vertexArrays.length - 1].values = weighta;
}
// Make vertex buffers
geom = new Geometry(this, indices, materialIndices, usage);
geom.name = name;
done(this);
}
public function delete() {
geom.delete();
}
public static function parse(name: String, id: String, done: MeshData->Void) {
Data.getSceneRaw(name, function(format: TSceneFormat) {
var raw: TMeshData = Data.getMeshRawByName(format.mesh_datas, id);
if (raw == null) {
trace('Mesh data "$id" not found!');
done(null);
}
new MeshData(raw, function(dat: MeshData) {
dat.format = format;
// Skinned
#if lnx_skin
if (raw.skin != null) {
dat.geom.initSkeletonTransforms(raw.skin.transformsI);
}
#end
done(dat);
});
});
}
function getVertexSize(vertex_data: String, padding: Int = 0): Int {
switch (vertex_data) {
case "short4norm": return 4 - padding;
case "short2norm": return 2 - padding;
default: return 0;
}
}
inline function getPadding(padding: Null<Int>): Int {
return padding != null ? padding : 0;
}
}