forked from LeenkxTeam/LNXSDK
		
	
		
			
				
	
	
		
			391 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
			
		
		
	
	
			391 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
| package iron.data;
 | |
| 
 | |
| import haxe.ds.Vector;
 | |
| import kha.graphics4.VertexBuffer;
 | |
| import kha.graphics4.IndexBuffer;
 | |
| import kha.graphics4.Usage;
 | |
| import kha.graphics4.VertexStructure;
 | |
| import kha.graphics4.VertexData;
 | |
| import kha.arrays.ByteArray;
 | |
| import kha.arrays.Float32Array;
 | |
| import kha.arrays.Uint32Array;
 | |
| import kha.arrays.Int16Array;
 | |
| import iron.math.Vec4;
 | |
| import iron.math.Mat4;
 | |
| import iron.data.SceneFormat;
 | |
| import iron.data.MeshData;
 | |
| 
 | |
| class Geometry {
 | |
| #if lnx_deinterleaved
 | |
| 	public var vertexBuffers: Vector<InterleavedVertexBuffer>;
 | |
| #else
 | |
| 	public var vertexBuffer: VertexBuffer;
 | |
| 	public var vertexBufferMap: Map<String, VertexBuffer> = new Map();
 | |
| #end
 | |
| 	public var indexBuffers: Array<IndexBuffer>;
 | |
| 	public var start = 0; // For drawIndexedVertices
 | |
| 	public var count = -1;
 | |
| 	public var name = "";
 | |
| 
 | |
| 	public var ready = false;
 | |
| 	public var vertices: ByteArray;
 | |
| 	public var indices: Array<Uint32Array>;
 | |
| 	public var numTris = 0;
 | |
| 	public var materialIndices: Array<Int>;
 | |
| 	public var struct: VertexStructure;
 | |
| 	public var structLength: Int;
 | |
| 	public var structStr: String;
 | |
| 	public var usage: Usage;
 | |
| 
 | |
| 	public var instancedVB: VertexBuffer = null;
 | |
| 	public var instanced = false;
 | |
| 	public var instanceCount = 0;
 | |
| 
 | |
| 	public var positions: TVertexArray;
 | |
| 	public var normals: TVertexArray;
 | |
| 	public var uvs: TVertexArray;
 | |
| 	public var cols: TVertexArray;
 | |
| 	public var vertexArrays: Array<TVertexArray>;
 | |
| 	var data: MeshData;
 | |
| 
 | |
| 	public var aabb: Vec4 = null;
 | |
| 	public var aabbMin: Vec4 = null;
 | |
| 	public var aabbMax: Vec4 = null;
 | |
| 
 | |
| 	// Skinned
 | |
| #if lnx_skin
 | |
| 	public var skeletonTransformsI: Array<Mat4> = null;
 | |
| #end
 | |
| 
 | |
| 	public function new(data: MeshData, indices: Array<Uint32Array>, materialIndices: Array<Int>, usage: Usage = null) {
 | |
| 		if (usage == null) usage = Usage.StaticUsage;
 | |
| 
 | |
| 		this.indices = indices;
 | |
| 		this.materialIndices = materialIndices;
 | |
| 		this.usage = usage;
 | |
| 
 | |
| 		this.vertexArrays = data.raw.vertex_arrays;
 | |
| 		this.positions = getVArray('pos');
 | |
| 		this.normals = getVArray('nor');
 | |
| 		this.uvs = getVArray('tex');
 | |
| 		this.cols = getVArray('col');
 | |
| 		this.data = data;
 | |
| 
 | |
| 		struct = getVertexStructure(vertexArrays);
 | |
| 		structLength = Std.int(struct.byteSize() / 2);
 | |
| 		structStr = "";
 | |
| 		for (e in struct.elements) structStr += e.name;
 | |
| 	}
 | |
| 
 | |
| 	public function delete() {
 | |
| #if lnx_deinterleaved
 | |
| 		for (buf in vertexBuffers) if (buf.buffer != null) buf.buffer.delete();
 | |
| #else
 | |
| 		for (buf in vertexBufferMap) if (buf != null) buf.delete();
 | |
| #end
 | |
| 		for (buf in indexBuffers) buf.delete();
 | |
| 	}
 | |
| 
 | |
| 	static function getVertexStructure(vertexArrays: Array<TVertexArray>): VertexStructure {
 | |
| 		var structure = new VertexStructure();
 | |
| 		for (i in 0...vertexArrays.length) {
 | |
| 			structure.add(vertexArrays[i].attrib, getVertexData(vertexArrays[i].data));
 | |
| 		}
 | |
| 		return structure;
 | |
| 	}
 | |
| 
 | |
| 	static function getVertexData(data: String): VertexData {
 | |
| 		switch (data) {
 | |
| 			case "short4norm": return VertexData.Short4Norm;
 | |
| 			case "short2norm": return VertexData.Short2Norm;
 | |
| 			default: return VertexData.Short4Norm;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public function applyScale(sx: Float, sy: Float, sz: Float) {
 | |
| 		data.scalePos *= sx;
 | |
| 	}
 | |
| 
 | |
| 	public function getVArray(name: String): TVertexArray {
 | |
| 		for (i in 0...vertexArrays.length) {
 | |
| 			if (vertexArrays[i].attrib == name) {
 | |
| 				return vertexArrays[i];
 | |
| 			}
 | |
| 		}
 | |
| 		return null;
 | |
| 	}
 | |
| 
 | |
| 	public function setupInstanced(data: Float32Array, instancedType: Int, usage: Usage) {
 | |
| 		var structure = new VertexStructure();
 | |
| 		structure.instanced = true;
 | |
| 		instanced = true;
 | |
| 		// pos, pos+rot, pos+scale, pos+rot+scale
 | |
| 		structure.add("ipos", kha.graphics4.VertexData.Float3);
 | |
| 		if (instancedType == 2 || instancedType == 4) {
 | |
| 			structure.add("irot", kha.graphics4.VertexData.Float3);
 | |
| 		}
 | |
| 		if (instancedType == 3 || instancedType == 4) {
 | |
| 			structure.add("iscl", kha.graphics4.VertexData.Float3);
 | |
| 		}
 | |
| 
 | |
| 		instanceCount = Std.int(data.length / Std.int(structure.byteSize() / 4));
 | |
| 		instancedVB = new VertexBuffer(instanceCount, structure, usage, 1);
 | |
| 		var vertices = instancedVB.lock();
 | |
| 		for (i in 0...Std.int(vertices.byteLength / 4)) vertices.setFloat32(i * 4, data[i]);
 | |
| 		instancedVB.unlock();
 | |
| 	}
 | |
| 
 | |
| 	public function copyVertices(vertices: ByteArray, offset = 0, fakeUVs = false) {
 | |
| 		buildVertices(vertices, vertexArrays, offset, fakeUVs);
 | |
| 	}
 | |
| 
 | |
| 	static function buildVertices(vertices: ByteArray, vertexArrays: Array<TVertexArray>, offset = 0, fakeUVs = false, uvsIndex = -1) {
 | |
| 		var numVertices = verticesCount(vertexArrays[0]);
 | |
| 		var di = -1 + offset;
 | |
| 		for (i in 0...numVertices) {
 | |
| 			for (va in 0...vertexArrays.length) {
 | |
| 				var l = vertexArrays[va].size;
 | |
| 				if (fakeUVs && va == uvsIndex) { // Add fake uvs if uvs where "asked" for but not found
 | |
| 					for (j in 0...l) vertices.setInt16(++di * 2, 0);
 | |
| 					continue;
 | |
| 				}
 | |
| 				for (o in 0...l) {
 | |
| 					vertices.setInt16(++di * 2, vertexArrays[va].values[i * l + o]);
 | |
| 				}
 | |
| 				if (vertexArrays[va].padding != null) {
 | |
| 					if (vertexArrays[va].padding == 1) {
 | |
| 						vertices.setInt16(++di * 2, 0);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public function getVerticesLength(): Int {
 | |
| 		var res = 0;
 | |
| 		for (i in 0...vertexArrays.length) {
 | |
| 			res += vertexArrays[i].values.length;
 | |
| 		}
 | |
| 		return res;
 | |
| 	}
 | |
| 
 | |
| #if lnx_deinterleaved
 | |
| 	public function get(vs: Array<TVertexElement>): Array<VertexBuffer> {
 | |
| 		var vbs = [];
 | |
| 		for (e in vs) {
 | |
| 			for (v in 0...vertexBuffers.length)
 | |
| 				if (vertexBuffers[v].name == e.name) {
 | |
| 					vbs.push(vertexBuffers[v].buffer);
 | |
| 					continue;
 | |
| 				}
 | |
| 			if (e.name == "ipos" && instancedVB != null) {
 | |
| 				vbs.push(instancedVB);
 | |
| 			}
 | |
| 		}
 | |
| 		return vbs;
 | |
| 	}
 | |
| #else
 | |
| 
 | |
| 	public function get(vs: Array<TVertexElement>): VertexBuffer {
 | |
| 		var key = "";
 | |
| 		for (e in vs) key += e.name;
 | |
| 		var vb = vertexBufferMap.get(key);
 | |
| 		if (vb == null) {
 | |
| 			var nVertexArrays = [];
 | |
| 			var atex = false;
 | |
| 			var texOffset = -1;
 | |
| 			var acol = false;
 | |
| 			for (e in 0...vs.length) {
 | |
| 				if (vs[e].name == "tex") {
 | |
| 					atex = true;
 | |
| 					texOffset = e;
 | |
| 				}
 | |
| 				if (vs[e].name == "col") {
 | |
| 					acol = true;
 | |
| 				}
 | |
| 				for (va in 0...vertexArrays.length) {
 | |
| 					if (vs[e].name == vertexArrays[va].attrib) {
 | |
| 						nVertexArrays.push(vertexArrays[va]);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			// Multi-mat mesh with different vertex structures
 | |
| 			var struct = getVertexStructure(nVertexArrays);
 | |
| 			vb = new VertexBuffer(Std.int(positions.values.length / positions.size), struct, usage);
 | |
| 			vertices = vb.lock();
 | |
| 			buildVertices(vertices, nVertexArrays, 0, atex && uvs == null, texOffset);
 | |
| 			vb.unlock();
 | |
| 			vertexBufferMap.set(key, vb);
 | |
| 			if (atex && uvs == null) trace("Leenkx Warning: Geometry " + name + " is missing UV map");
 | |
| 			if (acol && cols == null) trace("Leenkx Warning: Geometry " + name + " is missing vertex colors");
 | |
| 		}
 | |
| 		return vb;
 | |
| 	}
 | |
| #end
 | |
| 
 | |
| 	public function build() {
 | |
| 		if (ready) return;
 | |
| 
 | |
| #if lnx_deinterleaved
 | |
| 		var vaLength = vertexArrays.length;
 | |
| 		vertexBuffers = new Vector(vaLength);
 | |
| 		for (i in 0...vaLength)
 | |
| 			vertexBuffers[i] = {
 | |
| 				name: vertexArrays[i].attrib,
 | |
| 				buffer: makeDeinterleavedVB(vertexArrays[i].values, vertexArrays[i].attrib, vertexArrays[i].size)
 | |
| 			};
 | |
| #else
 | |
| 
 | |
| 		vertexBuffer = new VertexBuffer(Std.int(positions.values.length / positions.size), struct, usage);
 | |
| 		vertices = vertexBuffer.lock();
 | |
| 		buildVertices(vertices, vertexArrays);
 | |
| 		vertexBuffer.unlock();
 | |
| 		vertexBufferMap.set(structStr, vertexBuffer);
 | |
| #end
 | |
| 
 | |
| 		indexBuffers = [];
 | |
| 		for (id in indices) {
 | |
| 			if (id.length == 0) continue;
 | |
| 			var indexBuffer = new IndexBuffer(id.length, usage);
 | |
| 			numTris += Std.int(id.length / 3);
 | |
| 
 | |
| 			var indicesA = indexBuffer.lock();
 | |
| 			for (i in 0...indicesA.length) indicesA[i] = id[i];
 | |
| 
 | |
| 			indexBuffer.unlock();
 | |
| 			indexBuffers.push(indexBuffer);
 | |
| 		}
 | |
| 
 | |
| 		// Instanced
 | |
| 		if (data.raw.instanced_data != null) setupInstanced(data.raw.instanced_data, data.raw.instanced_type, usage);
 | |
| 
 | |
| 		ready = true;
 | |
| 	}
 | |
| 
 | |
| #if lnx_deinterleaved
 | |
| 	function makeDeinterleavedVB(data: ByteArray, name: String, structLength: Int): VertexBuffer {
 | |
| 		var struct = new VertexStructure();
 | |
| 		struct.add(name, structLength == 2 ? VertexData.Short2Norm : VertexData.Short4Norm);
 | |
| 
 | |
| 		var vertexBuffer = new VertexBuffer(Std.int(data.byteLength / 2 / structLength), struct, usage);
 | |
| 
 | |
| 		var vertices = vertexBuffer.lock();
 | |
| 		for (i in 0...Std.int(vertices.byteLength / 2)) vertices.setInt16(i * 2, data.getInt16(i * 2));
 | |
| 		vertexBuffer.unlock();
 | |
| 
 | |
| 		return vertexBuffer;
 | |
| 	}
 | |
| #end
 | |
| 
 | |
| 	public function getVerticesCount(): Int {
 | |
| 		return Std.int(positions.values.length / positions.size);
 | |
| 	}
 | |
| 
 | |
| 	inline static function verticesCount(arr: TVertexArray): Int {
 | |
| 		return Std.int(arr.values.length / arr.size);
 | |
| 	}
 | |
| 
 | |
| 	// Skinned
 | |
| #if lnx_skin
 | |
| 	public function initSkeletonTransforms(transformsI: Array<Float32Array>) {
 | |
| 		skeletonTransformsI = [];
 | |
| 		for (t in transformsI) {
 | |
| 			var mi = Mat4.fromFloat32Array(t);
 | |
| 			skeletonTransformsI.push(mi);
 | |
| 		}
 | |
| 	}
 | |
| #end
 | |
| 
 | |
| 	public function calculateAABB() {
 | |
| 		aabbMin = new Vec4(-0.01, -0.01, -0.01);
 | |
| 		aabbMax = new Vec4(0.01, 0.01, 0.01);
 | |
| 		aabb = new Vec4();
 | |
| 		var i = 0;
 | |
| 		while (i < positions.values.length) {
 | |
| 			if (positions.values[i    ] > aabbMax.x) aabbMax.x = positions.values[i];
 | |
| 			if (positions.values[i + 1] > aabbMax.y) aabbMax.y = positions.values[i + 1];
 | |
| 			if (positions.values[i + 2] > aabbMax.z) aabbMax.z = positions.values[i + 2];
 | |
| 			if (positions.values[i    ] < aabbMin.x) aabbMin.x = positions.values[i];
 | |
| 			if (positions.values[i + 1] < aabbMin.y) aabbMin.y = positions.values[i + 1];
 | |
| 			if (positions.values[i + 2] < aabbMin.z) aabbMin.z = positions.values[i + 2];
 | |
| 			i += 4;
 | |
| 		}
 | |
| 		aabb.x = (Math.abs(aabbMin.x) + Math.abs(aabbMax.x)) / 32767 * data.scalePos;
 | |
| 		aabb.y = (Math.abs(aabbMin.y) + Math.abs(aabbMax.y)) / 32767 * data.scalePos;
 | |
| 		aabb.z = (Math.abs(aabbMin.z) + Math.abs(aabbMax.z)) / 32767 * data.scalePos;
 | |
| 	}
 | |
| 
 | |
| 	public function calculateTangents() {
 | |
| 		// var num_verts = Std.int(positions.length / 4);
 | |
| 		// var tangents = new Float32Array(num_verts * 3);
 | |
| 		// var bitangents = new Float32Array(num_verts * 3);
 | |
| 		// for (ia in indices) {
 | |
| 		// 	var num_tris = Std.int(ia.length / 3);
 | |
| 		// 	for (i in 0...num_tris) {
 | |
| 		// 		var i0 = ia[i * 3    ];
 | |
| 		// 		var i1 = ia[i * 3 + 1];
 | |
| 		// 		var i2 = ia[i * 3 + 2];
 | |
| 		// 		var v0 = Vector((positions[i0 * 4], positions[i0 * 4 + 1], positions[i0 * 4 + 2]));
 | |
| 		// 		var v1 = Vector((positions[i1 * 4], positions[i1 * 4 + 1], positions[i1 * 4 + 2]));
 | |
| 		// 		var v2 = Vector((positions[i2 * 4], positions[i2 * 4 + 1], positions[i2 * 4 + 2]));
 | |
| 		// 		var uv0 = Vector((uvs[i0 * 2], uvs[i0 * 2 + 1]));
 | |
| 		// 		var uv1 = Vector((uvs[i1 * 2], uvs[i1 * 2 + 1]));
 | |
| 		// 		var uv2 = Vector((uvs[i2 * 2], uvs[i2 * 2 + 1]));
 | |
| 
 | |
| 		// 		var deltaPos1 = v1 - v0;
 | |
| 		// 		var deltaPos2 = v2 - v0;
 | |
| 		// 		var deltaUV1 = uv1 - uv0;
 | |
| 		// 		var deltaUV2 = uv2 - uv0;
 | |
| 		// 		var d = (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x);
 | |
| 		// 		var r = d != 0 ? 1.0 / d : 1.0;
 | |
| 		// 		var tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r;
 | |
| 		// 		var bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r;
 | |
| 
 | |
| 		// 		var tangents[i0 * 3    ] += tangent.x;
 | |
| 		// 		var tangents[i0 * 3 + 1] += tangent.y;
 | |
| 		// 		var tangents[i0 * 3 + 2] += tangent.z;
 | |
| 		// 		var tangents[i1 * 3    ] += tangent.x;
 | |
| 		// 		var tangents[i1 * 3 + 1] += tangent.y;
 | |
| 		// 		var tangents[i1 * 3 + 2] += tangent.z;
 | |
| 		// 		var tangents[i2 * 3    ] += tangent.x;
 | |
| 		// 		var tangents[i2 * 3 + 1] += tangent.y;
 | |
| 		// 		var tangents[i2 * 3 + 2] += tangent.z;
 | |
| 		// 		var bitangents[i0 * 3    ] += bitangent.x;
 | |
| 		// 		var bitangents[i0 * 3 + 1] += bitangent.y;
 | |
| 		// 		var bitangents[i0 * 3 + 2] += bitangent.z;
 | |
| 		// 		var bitangents[i1 * 3    ] += bitangent.x;
 | |
| 		// 		var bitangents[i1 * 3 + 1] += bitangent.y;
 | |
| 		// 		var bitangents[i1 * 3 + 2] += bitangent.z;
 | |
| 		// 		var bitangents[i2 * 3    ] += bitangent.x;
 | |
| 		// 		var bitangents[i2 * 3 + 1] += bitangent.y;
 | |
| 		// 		var bitangents[i2 * 3 + 2] += bitangent.z;
 | |
| 		// 	}
 | |
| 		// }
 | |
| 
 | |
| 		// // Orthogonalize
 | |
| 		// for (i in 0...num_verts) {
 | |
| 		// 	var t = Vector((tangents[i * 3], tangents[i * 3 + 1], tangents[i * 3 + 2]));
 | |
| 		// 	var b = Vector((bitangents[i * 3], bitangents[i * 3 + 1], bitangents[i * 3 + 2]));
 | |
| 		// 	var n = Vector((normals[i * 2], normals[i * 2 + 1], positions[i * 4 + 3] / scale_pos));
 | |
| 		// 	var v = t - n * n.dot(t);
 | |
| 		// 	v.normalize();
 | |
| 		// 	// Calculate handedness
 | |
| 		// 	var cnv = n.cross(v);
 | |
| 		// 	if (cnv.dot(b) < 0.0)
 | |
| 		// 		v = v * -1.0;
 | |
| 		// 	tangents[i * 3    ] = v.x;
 | |
| 		// 	tangents[i * 3 + 1] = v.y;
 | |
| 		// 	tangents[i * 3 + 2] = v.z;
 | |
| 		// }
 | |
| 	}
 | |
| }
 | |
| 
 | |
| #if js
 | |
| typedef InterleavedVertexBuffer = {
 | |
| #else
 | |
| @:structInit class InterleavedVertexBuffer {
 | |
| #end
 | |
| 	public var name: String;
 | |
| 	public var buffer: VertexBuffer;
 | |
| }
 |