MBHaxe/src/DtsObject.hx
2024-07-16 19:38:34 +05:30

1150 lines
34 KiB
Haxe

package src;
import h3d.prim.DynamicPrimitive;
import h3d.scene.MultiMaterial;
import shaders.EnvMap;
import h3d.shader.CubeMap;
import dts.TSDrawPrimitive;
import hxd.res.Sound;
import h3d.col.Bounds;
import src.TimeState;
import shaders.Billboard;
import collision.BoxCollisionEntity;
import shaders.DtsTexture;
import h3d.shader.AlphaMult;
import src.MarbleWorld;
import src.GameObject;
import collision.CollisionHull;
import collision.CollisionSurface;
import collision.CollisionEntity;
import hxd.FloatBuffer;
import src.DynamicPolygon;
import dts.Sequence;
import h3d.scene.Mesh;
import src.Polygon;
import h3d.prim.UV;
import h3d.Vector;
import h3d.Quat;
import dts.Node;
import h3d.mat.BlendMode;
import h3d.mat.Data.Wrap;
import h3d.mat.Texture;
import h3d.mat.Material;
import h3d.scene.Object;
import haxe.io.Path;
import src.ResourceLoader;
import dts.DtsFile;
import h3d.Matrix;
import src.Util;
import src.Resource;
import src.Console;
var DROP_TEXTURE_FOR_ENV_MAP = ['shapes/items/superjump.dts', 'shapes/items/antigravity.dts'];
var dtsMaterials = [
"oilslick" => {friction: 0.05, restitution: 0.5, force: 0.0},
"base.slick" => {friction: 0.05, restitution: 0.5, force: 0.0},
"ice.slick" => {friction: 0.05, restitution: 0.5, force: 0.0},
"bumper-rubber" => {friction: 0.5, restitution: 0.0, force: 15.0},
"triang-side" => {friction: 0.5, restitution: 0.0, force: 15.0},
"triang-top" => {friction: 0.5, restitution: 0.0, force: 15.0},
"pball-round-side" => {friction: 0.5, restitution: 0.0, force: 15.0},
"pball-round-top" => {friction: 0.5, restitution: 0.0, force: 15.0},
"pball-round-bottm" => {friction: 0.5, restitution: 0.0, force: 15.0}
];
typedef MaterialGeometry = {
var vertices:Array<Vector>;
var normals:Array<Vector>;
var uvs:Array<UV>;
var indices:Array<Int>;
}
@:structInit
@:publicFields
class SkinMeshData {
var meshIndex:Int;
var vertices:Array<Float>; // Turn THIS into a FloatBuffer
var normals:Array<Float>; // SAME HERE
var indices:Array<Int>;
var geometry:Object;
var primitives:Array<DynamicPolygon>;
}
@:publicFields
class DtsObject extends GameObject {
var dtsPath:String;
var directoryPath:String;
var dts:DtsFile;
var dtsResource:Resource<DtsFile>;
var level:MarbleWorld;
var materials:Array<Material> = [];
var materialInfos:Map<Material, Array<String>> = new Map();
var matNameOverride:Map<String, String> = new Map();
var sequenceKeyframeOverride:Array<Float> = [];
var lastSequenceKeyframes:Array<Float> = [];
var graphNodes:Array<Object> = [];
var dirtyTransforms:Array<Bool> = [];
var useInstancing:Bool = true;
var isTSStatic:Bool;
var showSequences:Bool = true;
var hasNonVisualSequences:Bool = true;
var isInstanced:Bool = false;
var _regenNormals:Bool = false;
var skinMeshData:SkinMeshData;
var rootObject:Object;
var colliders:Array<CollisionEntity>;
var boundingCollider:BoxCollisionEntity;
var mountPointNodes:Array<Int>;
var alphaShader:AlphaMult;
var ambientRotate = false;
var ambientSpinFactor = -1 / 3 * Math.PI * 2;
public var idInLevel:Int = -1;
public function new() {
super();
}
public function init(level:MarbleWorld, onFinish:Void->Void) {
this.dtsResource = ResourceLoader.loadDts(this.dtsPath);
this.dtsResource.acquire();
this.dts = this.dtsResource.resource;
this.directoryPath = Path.directory(this.dtsPath);
if (level != null)
this.level = level;
isInstanced = false;
if (!Util.isIOSInstancingSupported()) {
this.useInstancing = false;
}
if (this.level != null)
isInstanced = this.level.instanceManager.isInstanced(this) && useInstancing;
if (!isInstanced)
this.computeMaterials();
var graphNodes = [];
var rootNodesIdx = [];
colliders = [];
this.mountPointNodes = [for (i in 0...32) -1];
for (i in 0...this.dts.nodes.length) {
graphNodes.push(new Object());
}
for (i in 0...this.dts.nodes.length) {
var node = this.dts.nodes[i];
if (node.parent != -1) {
graphNodes[node.parent].addChild(graphNodes[i]);
} else {
rootNodesIdx.push(i);
}
}
this.graphNodes = graphNodes;
// this.rootGraphNodes = graphNodes.filter(node -> node.parent == null);
var affectedBySequences = this.dts.sequences.length > 0 ? (this.dts.sequences[0].rotationMatters.length < 0 ? 0 : this.dts.sequences[0].rotationMatters[0]) | (this.dts.sequences[0].translationMatters.length > 0 ? this.dts.sequences[0].translationMatters[0] : 0) : 0;
for (i in 0...dts.nodes.length) {
var objects = dts.objects.filter(object -> object.node == i);
var sequenceAffected = ((1 << i) & affectedBySequences) != 0;
if (dts.names[dts.nodes[i].name].substr(0, 5) == "mount") {
var mountindex = dts.names[dts.nodes[i].name].substr(5);
var mountNode = Std.parseInt(mountindex);
mountPointNodes[mountNode] = i;
}
for (object in objects) {
var isCollisionObject = dts.names[object.name].substr(0, 3).toLowerCase() == "col";
if (isCollisionObject)
continue;
for (j in object.firstMesh...(object.firstMesh + object.numMeshes)) {
if (j >= this.dts.meshes.length)
continue;
var mesh = this.dts.meshes[j];
if (mesh == null)
continue;
if (mesh.parent >= 0)
continue; // Fix teleporter being broken
if (mesh.vertices.length == 0)
continue;
if (!isInstanced) {
var vertices = mesh.vertices.map(v -> new Vector(-v.x, v.y, v.z));
var vertexNormals = mesh.normals.map(v -> new Vector(-v.x, v.y, v.z));
var geometry = this.generateMaterialGeometry(mesh, vertices, vertexNormals);
var poly = new Polygon();
var usedMats = [];
for (k in 0...geometry.length) {
if (geometry[k].vertices.length == 0)
continue;
poly.addPoints(geometry[k].vertices.map(x -> x.toPoint()));
poly.addNormals(geometry[k].normals.map(x -> x.toPoint()));
poly.addUVs(geometry[k].uvs);
poly.nextMaterial();
usedMats.push(materials[k]);
}
poly.endPrimitive();
var obj = new MultiMaterial(poly, usedMats, this.graphNodes[i]);
} else {
// var usedMats = [];
// for (prim in mesh.primitives) {
// if (!usedMats.contains(prim.matIndex)) {
// usedMats.push(prim.matIndex);
// }
// }
// for (k in usedMats) {
var obj = new Object(this.graphNodes[i]);
// }
}
}
}
}
if (this.isCollideable) {
for (i in 0...dts.nodes.length) {
var objects = dts.objects.filter(object -> object.node == i);
var localColliders:Array<CollisionEntity> = [];
for (object in objects) {
var isCollisionObject = dts.names[object.name].substr(0, 3).toLowerCase() == "col";
if (isCollisionObject) {
for (j in object.firstMesh...(object.firstMesh + object.numMeshes)) {
if (j >= this.dts.meshes.length)
continue;
var mesh = this.dts.meshes[j];
if (mesh == null)
continue;
var vertices = mesh.vertices.map(v -> new Vector(-v.x, v.y, v.z));
var vertexNormals = mesh.normals.map(v -> new Vector(-v.x, v.y, v.z));
var hulls = this.generateCollisionGeometry(mesh, vertices, vertexNormals, i);
localColliders = localColliders.concat(hulls);
}
}
}
colliders = colliders.concat(localColliders);
}
}
this.updateNodeTransforms();
for (i in 0...this.dts.meshes.length) {
var mesh = this.dts.meshes[i];
if (mesh == null)
continue;
if (mesh.meshType == 1) {
var skinObj = new Object();
if (!isInstanced) {
var vertices = mesh.vertices.map(v -> new Vector(-v.x, v.y, v.z));
var vertexNormals = mesh.normals.map(v -> new Vector(-v.x, v.y, v.z));
var geometry = this.generateMaterialGeometry(mesh, vertices, vertexNormals);
var prims = [];
for (k in 0...geometry.length) {
if (geometry[k].vertices.length == 0)
continue;
var poly = new DynamicPolygon();
poly.addPoints(geometry[k].vertices.map(x -> x.toPoint()));
poly.addNormals(geometry[k].normals.map(x -> x.toPoint()));
poly.addUVs(geometry[k].uvs);
var obj = new MultiMaterial(poly, [materials[k]], skinObj);
prims.push(poly);
}
var flatVerts = [];
var flatNormals = [];
for (v in vertices) {
flatVerts.push(v.x);
flatVerts.push(v.y);
flatVerts.push(v.z);
}
for (n in vertexNormals) {
flatNormals.push(n.x);
flatNormals.push(n.y);
flatNormals.push(n.z);
}
skinMeshData = {
meshIndex: i,
vertices: flatVerts,
normals: flatNormals,
indices: [],
geometry: skinObj,
primitives: prims
};
var idx = geometry.map(x -> x.indices);
for (indexes in idx) {
skinMeshData.indices = skinMeshData.indices.concat(indexes);
}
} else {
var usedMats = [];
for (prim in mesh.primitives) {
if (!usedMats.contains(prim.matIndex)) {
usedMats.push(prim.matIndex);
}
}
for (k in usedMats) {
var obj = new Object(skinObj);
}
skinMeshData = {
meshIndex: i,
vertices: [],
normals: [],
indices: [],
geometry: skinObj,
primitives: []
};
}
}
}
for (seq in this.dts.sequences) {
lastSequenceKeyframes.push(0);
sequenceKeyframeOverride.push(-1);
}
if (!this.isInstanced) {
for (i in 0...this.materials.length) {
var info = this.materialInfos.get(this.materials[i]);
if (info == null)
continue;
var iflSequence = this.dts.sequences.filter(seq -> seq.iflMatters.length > 0 ? seq.iflMatters[0] > 0 : false);
if (iflSequence.length == 0)
continue;
var completion = 0 / (iflSequence[0].duration);
var keyframe = Math.floor(completion * info.length) % info.length;
var currentFile = info[keyframe];
var texture = ResourceLoader.getResource(this.directoryPath + '/' + currentFile, ResourceLoader.getTexture, this.textureResources);
var flags = this.dts.matFlags[i];
if (flags & 1 > 0 || flags & 2 > 0)
texture.wrap = Wrap.Repeat;
this.materials[i].texture = texture;
}
}
rootObject = new Object(this);
for (i in rootNodesIdx) {
rootObject.addChild(this.graphNodes[i]);
}
if (this.skinMeshData != null) {
rootObject.addChild(this.skinMeshData.geometry);
}
// rootObject.scaleX = -1;
if (this.level != null && this.isBoundingBoxCollideable) {
var boundthing = new Bounds();
for (mesh in this.dts.meshes) {
if (mesh == null)
continue;
for (pt in mesh.vertices)
boundthing.addPoint(new h3d.col.Point(-pt.x, pt.y, pt.z));
}
boundthing.addPoint(new h3d.col.Point(-this.dts.bounds.minX, this.dts.bounds.minY, this.dts.bounds.minZ));
boundthing.addPoint(new h3d.col.Point(-this.dts.bounds.maxX, this.dts.bounds.maxY, this.dts.bounds.maxZ));
this.boundingCollider = new BoxCollisionEntity(boundthing, cast this);
this.boundingCollider.setTransform(this.getTransform());
}
this.dirtyTransforms = [];
for (i in 0...graphNodes.length) {
this.dirtyTransforms.push(true);
}
onFinish();
}
function computeMaterials() {
var environmentMaterial:Material = null;
for (i in 0...dts.matNames.length) {
var matName = matNameOverride.exists(dts.matNames[i]) ? matNameOverride.get(dts.matNames[i]) : this.dts.matNames[i];
var flags = dts.matFlags[i];
var fullNames = ResourceLoader.getFullNamesOf(this.directoryPath + '/' + matName).filter(x -> Path.extension(x) != "dts");
var fullName = fullNames.length > 0 ? fullNames[0] : null;
if (this.isTSStatic && environmentMaterial != null && DROP_TEXTURE_FOR_ENV_MAP.contains(this.dtsPath)) {
this.materials.push(environmentMaterial);
continue;
}
var material = Material.create();
var iflMaterial = false;
if (fullName == null || (this.isTSStatic && ((flags & (1 << 31) > 0)))) {
if (this.isTSStatic) {
material.mainPass.enableLights = false;
if (flags & (1 << 31) > 0) {
environmentMaterial = material;
}
// Console.warn('Unsupported material type for ${fullName}, dts: ${this.dtsPath}');
// TODO USE PBR???
}
} else if (Path.extension(fullName) == "ifl") {
var keyframes = parseIfl(fullName);
this.materialInfos.set(material, keyframes);
iflMaterial = true;
} else {
var texture = ResourceLoader.getResource(fullName, ResourceLoader.getTexture, this.textureResources);
texture.wrap = Wrap.Repeat;
material.texture = texture;
if (this.identifier != "Marble") {
var dtsshader = new DtsTexture();
dtsshader.texture = texture;
dtsshader.currentOpacity = 1;
if (this.identifier == "Tornado")
dtsshader.normalizeNormals = false; // These arent normalized
if (this.identifier != null && StringTools.startsWith(this.identifier, "GemBeam")) {
dtsshader.usePremultipliedAlpha = true;
dtsshader.opacityMult = 3.0; // Hardcoded
}
material.mainPass.removeShader(material.textureShader);
material.mainPass.addShader(dtsshader);
}
// TODO TRANSLUENCY SHIT
}
material.shadows = false;
if (this.isCollideable)
material.receiveShadows = false;
if (material.texture == null && !iflMaterial) {
var dtsshader = new DtsTexture();
dtsshader.currentOpacity = 1;
if (this.identifier == "Tornado")
dtsshader.normalizeNormals = false; // These arent normalized
// Make a 1x1 white texture
#if hl
var bitmap = new hxd.BitmapData(1, 1);
bitmap.lock();
bitmap.setPixel(0, 0, 0xFFFFFF);
bitmap.unlock();
var texture = new Texture(1, 1);
texture.uploadBitmap(bitmap);
texture.wrap = Wrap.Repeat;
#end
// Apparently creating these bitmap datas dont work so we'll just get the snag a white texture in the filesystem
#if js
var texture:Texture = ResourceLoader.getResource("data/shapes/pads/white.jpg", ResourceLoader.getTexture, this.textureResources);
texture.wrap = Wrap.Repeat;
#end
Console.warn('Unable to load ${matName}');
material.texture = texture;
dtsshader.texture = texture;
material.mainPass.addShader(dtsshader);
material.shadows = false;
}
if (flags & 4 > 0) {
if (this.identifier == null || !StringTools.startsWith(this.identifier, "GemBeam")) {
material.blendMode = BlendMode.Alpha;
material.mainPass.culling = h3d.mat.Data.Face.None;
material.receiveShadows = false;
material.mainPass.depthWrite = false;
}
if (this.identifier != null && StringTools.startsWith(this.identifier, "GemBeam")) {
material.blendMode = BlendMode.Alpha;
material.mainPass.culling = h3d.mat.Data.Face.None;
material.receiveShadows = false;
material.mainPass.blend(SrcAlpha, OneMinusSrcAlpha);
material.mainPass.depthWrite = false;
}
}
if (flags & 8 > 0) {
material.blendMode = BlendMode.Add;
}
if (flags & 16 > 0) {
material.blendMode = BlendMode.Sub;
}
if (flags & 32 > 0) {
material.mainPass.enableLights = false;
material.receiveShadows = false;
}
if (this.isTSStatic && !(flags & 64 > 0)) {
var reflectivity = this.dts.matNames.length == 1 ? 1 : (environmentMaterial != null ? 0.5 : 0.333);
var cubemapshader = new EnvMap(this.level.sky.cubemap, reflectivity);
material.mainPass.addShader(cubemapshader);
}
this.materials.push(material);
}
if (this.materials.length == 0) {
#if hl
var bitmap = new hxd.BitmapData(1, 1);
bitmap.lock();
bitmap.setPixel(0, 0, 0xFFFFFF);
bitmap.unlock();
var texture = new Texture(1, 1);
texture.uploadBitmap(bitmap);
texture.wrap = Wrap.Repeat;
#end
// Apparently creating these bitmap datas dont work so we'll just get the snag a white texture in the filesystem
#if js
var texture:Texture = ResourceLoader.getResource("data/shapes/pads/white.jpg", ResourceLoader.getTexture, this.textureResources);
texture.wrap = Wrap.Repeat;
#end
var dtsshader = new DtsTexture();
var mat = Material.create();
mat.texture = texture;
dtsshader.texture = texture;
mat.mainPass.addShader(dtsshader);
mat.shadows = false;
this.materials.push(mat);
Console.warn('No materials found for ${this.dtsPath}}');
// TODO THIS
}
}
function parseIfl(path:String) {
var text = ResourceLoader.getFileEntry(path).entry.getText();
var lines = text.split('\n');
var keyframes = [];
for (line in lines) {
line = StringTools.trim(line);
if (line.substr(0, 2) == "//")
continue;
if (line == "")
continue;
var parts = line.split(' ');
var count = parts.length > 1 ? Std.parseInt(parts[1]) : 1;
for (i in 0...count) {
keyframes.push(parts[0]);
}
}
return keyframes;
}
function updateNodeTransforms(quaternions:Array<Quat> = null, translations:Array<Vector> = null, bitField = 0xffffffff) {
for (i in 0...this.graphNodes.length) {
var translation = this.dts.defaultTranslations[i];
var rotation = this.dts.defaultRotations[i];
var mat = Matrix.I();
var quat = new Quat(-rotation.x, rotation.y, rotation.z, -rotation.w);
quat.normalize();
quat.conjugate();
quat.toMatrix(mat);
mat.setPosition(new Vector(-translation.x, translation.y, translation.z));
this.graphNodes[i].setTransform(mat);
var absTform = this.graphNodes[i].getAbsPos().clone();
if (this.colliders[i] != null)
// this.colliders[i].setTransform(Matrix.I());
this.colliders[i].setTransform(absTform);
}
}
function generateCollisionGeometry(dtsMesh:dts.Mesh, vertices:Array<Vector>, vertexNormals:Array<Vector>, node:Int) {
var hulls:Array<CollisionEntity> = [new CollisionEntity(cast this)];
var ent = hulls[0];
ent.userData = node;
for (primitive in dtsMesh.primitives) {
var k = 0;
// var chull = new CollisionEntity(cast this); // new CollisionHull(cast this);
// chull.userData = node;
var hs = new CollisionSurface();
hs.points = [];
hs.normals = [];
hs.indices = [];
hs.transformKeys = [];
var material = this.dts.matNames[primitive.matIndex & TSDrawPrimitive.MaterialMask];
if (dtsMaterials.exists(material) && !this.isTSStatic) {
var data = dtsMaterials.get(material);
hs.friction = data.friction;
hs.force = data.force;
hs.restitution = data.restitution;
}
var drawType = primitive.matIndex & TSDrawPrimitive.TypeMask;
if (drawType == TSDrawPrimitive.Triangles) {
var i = primitive.firstElement;
while (i < primitive.firstElement + primitive.numElements) {
var i1 = dtsMesh.indices[i];
var i2 = dtsMesh.indices[i + 1];
var i3 = dtsMesh.indices[i + 2];
var t1 = vertices[i2].sub(vertices[i1]);
var t2 = vertices[i3].sub(vertices[i1]);
var tarea = Math.abs(t1.cross(t2).length()) / 2.0;
if (tarea < 0.00001)
continue;
for (index in [i1, i2, i3]) {
var vertex = vertices[index];
hs.addPoint(vertex.x, vertex.y, vertex.z);
hs.transformKeys.push(0);
var normal = vertexNormals[index];
hs.addNormal(normal.x, normal.y, normal.z);
}
hs.indices.push(hs.indices.length);
hs.indices.push(hs.indices.length);
hs.indices.push(hs.indices.length);
i += 3;
}
} else if (drawType == TSDrawPrimitive.Strip) {
var k = 0;
for (i in primitive.firstElement...(primitive.firstElement + primitive.numElements - 2)) {
var i1 = dtsMesh.indices[i];
var i2 = dtsMesh.indices[i + 1];
var i3 = dtsMesh.indices[i + 2];
if (k % 2 == 0) {
// Swap the first and last index to mainting correct winding order
var temp = i1;
i1 = i3;
i3 = temp;
}
var t1 = vertices[i2].sub(vertices[i1]);
var t2 = vertices[i3].sub(vertices[i1]);
var tarea = Math.abs(t1.cross(t2).length()) / 2.0;
if (tarea < 0.00001)
continue;
for (index in [i1, i2, i3]) {
var vertex = vertices[index];
hs.addPoint(vertex.x, vertex.y, vertex.z);
hs.transformKeys.push(0);
var normal = vertexNormals[index];
hs.addNormal(normal.x, normal.y, normal.z);
}
hs.indices.push(hs.indices.length);
hs.indices.push(hs.indices.length);
hs.indices.push(hs.indices.length);
k++;
}
} else if (drawType == TSDrawPrimitive.Fan) {
var i = primitive.firstElement;
while (i < primitive.firstElement + primitive.numElements - 2) {
var i1 = dtsMesh.indices[primitive.firstElement];
var i2 = dtsMesh.indices[i + 1];
var i3 = dtsMesh.indices[i + 2];
var t1 = vertices[i2].sub(vertices[i1]);
var t2 = vertices[i3].sub(vertices[i1]);
var tarea = Math.abs(t1.cross(t2).length()) / 2.0;
if (tarea < 0.00001)
continue;
for (index in [i1, i2, i3]) {
var vertex = vertices[index];
hs.addPoint(vertex.x, vertex.y, vertex.z);
hs.transformKeys.push(0);
var normal = vertexNormals[index];
hs.addNormal(normal.x, normal.y, normal.z);
}
hs.indices.push(hs.indices.length);
hs.indices.push(hs.indices.length);
hs.indices.push(hs.indices.length);
i++;
}
}
hs.generateBoundingBox();
ent.addSurface(hs);
// chull.generateBoundingBox();
// chull.finalize();
// hulls.push(chull);
}
ent.generateBoundingBox();
ent.finalize();
return hulls;
}
function generateMaterialGeometry(dtsMesh:dts.Mesh, vertices:Array<Vector>, vertexNormals:Array<Vector>) {
var materialGeometry:Array<MaterialGeometry> = this.dts.matNames.map(x -> {
vertices: [],
normals: [],
uvs: [],
indices: []
});
if (materialGeometry.length == 0 && dtsMesh.primitives.length > 0) {
materialGeometry.push({
vertices: [],
normals: [],
uvs: [],
indices: []
});
}
var ab = new Vector();
var ac = new Vector();
function addTriangleFromIndices(i1:Int, i2:Int, i3:Int, materialIndex:Int) {
ab.set(vertices[i2].x - vertices[i1].x, vertices[i2].y - vertices[i1].y, vertices[i2].z - vertices[i1].z);
ac.set(vertices[i3].x - vertices[i1].x, vertices[i3].y - vertices[i1].y, vertices[i3].z - vertices[i1].z);
var normal = ab.cross(ac);
normal.normalize();
var dot1 = normal.dot(vertexNormals[i1]);
var dot2 = normal.dot(vertexNormals[i2]);
var dot3 = normal.dot(vertexNormals[i3]);
// if (!StringTools.contains(this.dtsPath, 'helicopter.dts') && !StringTools.contains(this.dtsPath, 'tornado.dts'))
// ^ temp hardcoded fix
// if (dot1 < 0 && dot2 < 0 && dot3 < 0) {
if ((dot1 < 0 && dot2 < 0 && dot3 < 0) || StringTools.contains(this.dtsPath, 'helicopter.dts')) {
var temp = i1;
i1 = i3;
i3 = temp;
}
// }
var geometrydata = materialGeometry[materialIndex];
for (index in [i1, i2, i3]) {
var vertex = vertices[index];
geometrydata.vertices.push(new Vector(vertex.x, vertex.y, vertex.z));
var uv = dtsMesh.uv[index];
geometrydata.uvs.push(new UV(uv.x, uv.y));
var normal = vertexNormals[index];
geometrydata.normals.push(new Vector(normal.x, normal.y, normal.z));
}
geometrydata.indices.push(i1);
geometrydata.indices.push(i2);
geometrydata.indices.push(i3);
}
for (primitive in dtsMesh.primitives) {
var materialIndex = primitive.matIndex & TSDrawPrimitive.MaterialMask;
var drawType = primitive.matIndex & TSDrawPrimitive.TypeMask;
var geometrydata = materialGeometry[materialIndex];
if (drawType == TSDrawPrimitive.Triangles) {
var i = primitive.firstElement;
while (i < primitive.firstElement + primitive.numElements) {
var i1 = dtsMesh.indices[i];
var i2 = dtsMesh.indices[i + 1];
var i3 = dtsMesh.indices[i + 2];
addTriangleFromIndices(i1, i2, i3, materialIndex);
i += 3;
}
} else if (drawType == TSDrawPrimitive.Strip) {
var k = 0;
for (i in primitive.firstElement...(primitive.firstElement + primitive.numElements - 2)) {
var i1 = dtsMesh.indices[i];
var i2 = dtsMesh.indices[i + 1];
var i3 = dtsMesh.indices[i + 2];
if (k % 2 == 0) {
// Swap the first and last index to mainting correct winding order
var temp = i1;
i1 = i3;
i3 = temp;
}
addTriangleFromIndices(i1, i2, i3, materialIndex);
k++;
}
} else if (drawType == TSDrawPrimitive.Fan) {
var i = primitive.firstElement;
while (i < primitive.firstElement + primitive.numElements - 2) {
var i1 = dtsMesh.indices[primitive.firstElement];
var i2 = dtsMesh.indices[i + 1];
var i3 = dtsMesh.indices[i + 2];
addTriangleFromIndices(i1, i2, i3, materialIndex);
i++;
}
}
}
return materialGeometry;
}
public override function setTransform(mat:Matrix) {
super.setTransform(mat);
if (this.isBoundingBoxCollideable) {
this.boundingCollider.setTransform(mat);
this.level.collisionWorld.updateTransform(this.boundingCollider);
}
for (i in 0...this.dirtyTransforms.length) {
this.dirtyTransforms[i] = true;
}
}
public function update(timeState:TimeState) {
if (this.currentOpacity == 0)
return;
for (i in 0...this.dts.sequences.length) {
var sequence = this.dts.sequences[i];
if (!this.showSequences)
break;
if (!this.hasNonVisualSequences)
break;
var rot = sequence.rotationMatters.length > 0 ? sequence.rotationMatters[0] : 0;
var trans = sequence.translationMatters.length > 0 ? sequence.translationMatters[0] : 0;
var scale = sequence.scaleMatters.length > 0 ? sequence.scaleMatters[0] : 0;
var affectedCount = 0;
var completion = timeState.timeSinceLoad / sequence.duration;
var quaternions:Array<Quat> = null;
var translations:Array<Vector> = null;
var scales:Array<Vector> = null;
var actualKeyframe = this.sequenceKeyframeOverride[i] != -1 ? this.sequenceKeyframeOverride[i] : ((completion * sequence.numKeyFrames) % sequence.numKeyFrames);
if (lastSequenceKeyframes[i] == actualKeyframe)
continue;
lastSequenceKeyframes[i] = actualKeyframe;
var keyframeLow = Math.floor(actualKeyframe);
var keyframeHigh = Math.ceil(actualKeyframe) % sequence.numKeyFrames;
var t = (actualKeyframe - keyframeLow) % 1;
if (rot > 0) {
quaternions = [];
for (i in 0...this.dts.nodes.length) {
var affected = ((1 << i) & rot) != 0;
if (affected) {
var rot1 = this.dts.nodeRotations[sequence.numKeyFrames * affectedCount + keyframeLow];
var rot2 = this.dts.nodeRotations[sequence.numKeyFrames * affectedCount + keyframeHigh];
var q1 = new Quat(-rot1.x, rot1.y, rot1.z, -rot1.w);
q1.normalize();
q1.conjugate();
var q2 = new Quat(-rot2.x, rot2.y, rot2.z, -rot2.w);
q2.normalize();
q2.conjugate();
var quat = new Quat();
quat.slerp(q1, q2, t);
quat.normalize();
this.graphNodes[i].getRotationQuat().load(quat);
this.graphNodes[i].posChanged = true;
this.dirtyTransforms[i] = true;
affectedCount++;
// quaternions.push(quat);
} else {
var rotation = this.dts.defaultRotations[i];
var quat = new Quat(-rotation.x, rotation.y, rotation.z, -rotation.w);
quat.normalize();
quat.conjugate();
this.graphNodes[i].getRotationQuat().load(quat);
this.graphNodes[i].posChanged = true;
// quaternions.push(quat);
}
}
}
affectedCount = 0;
if (trans > 0) {
translations = [];
for (i in 0...this.dts.nodes.length) {
var affected = ((1 << i) & trans) != 0;
if (affected) {
var trans1 = this.dts.nodeTranslations[sequence.numKeyFrames * affectedCount + keyframeLow];
var trans2 = this.dts.nodeTranslations[sequence.numKeyFrames * affectedCount + keyframeHigh];
var v1 = new Vector(-trans1.x, trans1.y, trans1.z);
var v2 = new Vector(-trans2.x, trans2.y, trans2.z);
var trans = Util.lerpThreeVectors(v1, v2, t);
this.graphNodes[i].setPosition(trans.x, trans.y, trans.z);
this.dirtyTransforms[i] = true;
// translations.push(Util.lerpThreeVectors(v1, v2, t));
} else {
var translation = this.dts.defaultTranslations[i];
var trans = new Vector(-translation.x, translation.y, translation.z);
this.graphNodes[i].setPosition(trans.x, trans.y, trans.z);
// translations.push();
}
}
}
if (scale > 0) {
scales = [];
for (i in 0...this.dts.nodes.length) {
var affected = ((1 << i) & scale) != 0;
if (affected) {
var scale1 = this.dts.nodeAlignedScales[sequence.numKeyFrames * affectedCount + keyframeLow];
var scale2 = this.dts.nodeAlignedScales[sequence.numKeyFrames * affectedCount + keyframeHigh];
var v1 = new Vector(scale1.x, scale1.y, scale1.z);
var v2 = new Vector(scale2.x, scale2.y, scale2.z);
var scaleVec = Util.lerpThreeVectors(v1, v2, t);
this.graphNodes[i].scaleX = scaleVec.x;
this.graphNodes[i].scaleY = scaleVec.y;
this.graphNodes[i].scaleZ = scaleVec.z;
this.dirtyTransforms[i] = true;
} else {
this.graphNodes[i].scaleX = 1;
this.graphNodes[i].scaleY = 1;
this.graphNodes[i].scaleZ = 1;
}
}
}
}
if (this.skinMeshData != null && !isInstanced) {
var info = this.skinMeshData;
var mesh = this.dts.meshes[info.meshIndex];
for (i in 0...info.vertices.length) {
info.vertices[i] = 0;
info.normals[i] = 0;
}
var boneTransformations = [];
for (i in 0...mesh.nodeIndices.length) {
var mat = mesh.initialTransforms[i].clone();
mat.scale(-1);
mat.transpose();
var tform = this.graphNodes[mesh.nodeIndices[i]].getRelPos(this).clone();
tform.prependScale(-1);
mat.multiply(mat, tform);
boneTransformations.push(mat);
}
for (i in 0...mesh.vertexIndices.length) {
var vIndex = mesh.vertexIndices[i];
var vertex = mesh.vertices[vIndex];
var normal = mesh.normals[vIndex];
var vec = new Vector();
var vec2 = new Vector();
vec.set(-vertex.x, vertex.y, vertex.z);
vec2.set(-normal.x, normal.y, normal.z);
var mat = boneTransformations[mesh.boneIndices[i]];
vec.transform(mat);
vec.load(vec.multiply(mesh.weights[i]));
Util.m_matF_x_vectorF(mat, vec2);
vec2.load(vec2.multiply(mesh.weights[i]));
info.vertices[3 * vIndex] = info.vertices[3 * vIndex] + vec.x;
info.vertices[3 * vIndex + 1] = info.vertices[3 * vIndex + 1] + vec.y;
info.vertices[3 * vIndex + 2] = info.vertices[3 * vIndex + 2] + vec.z;
info.normals[3 * vIndex] = info.normals[3 * vIndex] + vec2.x;
info.normals[3 * vIndex + 1] = info.normals[3 * vIndex + 1] + vec2.y;
info.normals[3 * vIndex + 2] = info.normals[3 * vIndex + 2] + vec2.z;
}
for (i in 0...Std.int(info.normals.length / 3)) {
var norm = new Vector(info.normals[3 * i], info.normals[3 * i + 1], info.normals[3 * i + 2]);
var len2 = norm.dot(norm);
if (len2 > 0.01) {
norm.normalize();
info.normals[3 * i] = norm.x;
info.normals[3 * i + 1] = norm.y;
info.normals[3 * i + 2] = norm.z;
}
}
var meshIndex = 0;
var prim = info.primitives[meshIndex];
var pos = 0;
for (i in info.indices) {
if (pos >= Std.int(prim.points.length / 3)) {
meshIndex++;
prim = info.primitives[meshIndex];
pos = 0;
}
prim.points[3 * pos] = info.vertices[3 * i];
prim.points[3 * pos + 1] = info.vertices[3 * i + 1];
prim.points[3 * pos + 2] = info.vertices[3 * i + 2];
prim.normals[3 * pos] = info.normals[3 * i];
prim.normals[3 * pos + 1] = info.normals[3 * i + 1];
prim.normals[3 * pos + 2] = info.normals[3 * i + 2];
if (prim.buffer != null) {
prim.dirtyFlags[pos] = true;
}
pos++;
}
if (prim.buffer != null) {
// prim.addNormals();
// for (norm in prim.normals)
// norm = norm.multiply(-1);
prim.flush();
}
if (_regenNormals) {
_regenNormals = false;
}
}
if (!this.isInstanced && !this.isTSStatic) {
for (i in 0...this.materials.length) {
var info = this.materialInfos.get(this.materials[i]);
if (info == null)
continue;
var iflSequence = this.dts.sequences.filter(seq -> seq.iflMatters.length > 0 ? seq.iflMatters[0] > 0 : false);
if (iflSequence.length == 0 || !this.showSequences)
continue;
var completion = timeState.timeSinceLoad / (iflSequence[0].duration);
var keyframe = Math.floor(completion * info.length) % info.length;
var currentFile = info[keyframe];
var texture = ResourceLoader.getResource(this.directoryPath + '/' + currentFile, ResourceLoader.getTexture, this.textureResources);
var flags = this.dts.matFlags[i];
if (flags & 1 > 0 || flags & 2 > 0)
texture.wrap = Wrap.Repeat;
this.materials[i].texture = texture;
}
}
if (this.ambientRotate) {
var spinAnimation = new Quat();
spinAnimation.initRotateAxis(0, 0, -1, timeState.timeSinceLoad * this.ambientSpinFactor);
// var orientation = this.getRotationQuat();
// spinAnimation.multiply(orientation, spinAnimation);
this.rootObject.getRotationQuat().load(spinAnimation);
this.rootObject.posChanged = true;
// setRotationQuat(spinAnimation);
}
for (i in 0...this.colliders.length) {
if (this.dirtyTransforms[this.colliders[i].userData]) {
var absTform = this.graphNodes[this.colliders[i].userData].getAbsPos();
if (this.colliders[i] != null) {
this.colliders[i].setTransform(absTform);
this.level.collisionWorld.updateTransform(this.colliders[i]);
}
}
}
for (i in 0...this.dirtyTransforms.length) {
this.dirtyTransforms[i] = false;
}
}
public function getMountTransform(mountPoint:Int) {
if (mountPoint < 32) {
var ni = mountPointNodes[mountPoint];
if (ni != -1) {
var mtransform = this.graphNodes[ni].getAbsPos();
return mtransform;
}
}
return this.getTransform();
}
public function setOpacity(opacity:Float) {
if (opacity == this.currentOpacity)
return;
this.currentOpacity = opacity;
if (!this.useInstancing) {
for (material in this.materials) {
if (this.currentOpacity != 1) {
material.blendMode = BlendMode.Alpha;
if (this.alphaShader == null) {
this.alphaShader = new AlphaMult();
}
if (material.mainPass.getShader(AlphaMult) == null) {
material.mainPass.addShader(this.alphaShader);
}
this.alphaShader.alpha = this.currentOpacity;
} else {
if (alphaShader != null) {
material.blendMode = BlendMode.None;
alphaShader.alpha = this.currentOpacity;
material.mainPass.removeShader(alphaShader);
}
}
}
}
}
public function setHide(hide:Bool) {
if (hide) {
this.setCollisionEnabled(false);
this.setOpacity(0);
} else {
this.setCollisionEnabled(true);
this.setOpacity(1);
}
}
public function setCollisionEnabled(flag:Bool) {
this.isCollideable = flag;
}
public override function dispose() {
super.dispose();
this.level = null;
boundingCollider = null;
colliders = null;
this.dtsResource.release();
}
}