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 = []; var materialIndices: Array = []; 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 { return padding != null ? padding : 0; } }