public LightNode(Stream mdlStream, Stream mdxStream, Type nodeType, AuroraModel model) : base(mdlStream, mdxStream, nodeType, model) { byte[] buffer = new byte[92]; mdlStream.Read(buffer, 0, 92); flareRadius = BitConverter.ToSingle(buffer, 0); unknown = new uint[3]; for (int i = 0; i < 3; i++) { unknown[i] = BitConverter.ToUInt32(buffer, 4 + (i * 4)); } flareSize = new Vector3(BitConverter.ToSingle(buffer, 16), BitConverter.ToSingle(buffer, 20), BitConverter.ToSingle(buffer, 24)); flarePos = new Vector3(BitConverter.ToSingle(buffer, 28), BitConverter.ToSingle(buffer, 32), BitConverter.ToSingle(buffer, 36)); flareColorShifts = new Vector3(BitConverter.ToSingle(buffer, 40), BitConverter.ToSingle(buffer, 44), BitConverter.ToSingle(buffer, 48)); pointerArray = new byte[12]; for (int i = 0; i < 12; i++) { pointerArray[i] = buffer[52 + i]; } priority = BitConverter.ToUInt32(buffer, 64); ambientFlag = BitConverter.ToUInt32(buffer, 68); dynamicFlag = BitConverter.ToUInt32(buffer, 72); affectDynamicFlag = BitConverter.ToUInt32(buffer, 76); shadowFlag = BitConverter.ToUInt32(buffer, 80); generateFlareFlag = BitConverter.ToUInt32(buffer, 84); fadingLightFlag = BitConverter.ToUInt32(buffer, 88); }
public Node(Stream mdlStream, Stream mdxStream, Type nodeType, AuroraModel model) { byte[] buffer = new byte[78]; mdlStream.Read(buffer, 0, 78); this.nodeType = nodeType; model.nodes.Add(this); superIndex = BitConverter.ToUInt16(buffer, 0); ushort nameIndex = BitConverter.ToUInt16(buffer, 2); name = (nameIndex < model.nodeNames.Length) ? model.nodeNames[nameIndex] : ""; //get the node's position, flip the y and z co-ordinates to align with Unity axes position = new Vector3(BitConverter.ToSingle(buffer, 14), BitConverter.ToSingle(buffer, 22), BitConverter.ToSingle(buffer, 18)); //get the node's orientation, and invert align with Unity axes Quaternion rot = new Quaternion(BitConverter.ToSingle(buffer, 30), BitConverter.ToSingle(buffer, 34), BitConverter.ToSingle(buffer, 38), BitConverter.ToSingle(buffer, 26)); Quaternion inv = new Quaternion(-rot.x, -rot.z, -rot.y, rot.w); rotation = inv; uint childArrayOffset = BitConverter.ToUInt32(buffer, 42), childArrayCount = BitConverter.ToUInt32(buffer, 46), childArrayCapacity = BitConverter.ToUInt32(buffer, 50); uint curveKeyArrayOffset = BitConverter.ToUInt32(buffer, 54), curveKeyArrayCount = BitConverter.ToUInt32(buffer, 58), curveKeyArrayCapacity = BitConverter.ToUInt32(buffer, 62); uint curveDataArrayOffset = BitConverter.ToUInt32(buffer, 66), curveDataArrayCount = BitConverter.ToUInt32(buffer, 70), curveDataArrayCapacity = BitConverter.ToUInt32(buffer, 74); long pos = mdlStream.Position; //an array of offsets into the node list for each child of this node uint[] childArray = new uint[childArrayCount]; mdlStream.Position = model.modelDataOffset + childArrayOffset; buffer = new byte[4 * childArrayCount]; mdlStream.Read(buffer, 0, 4 * (int)childArrayCount); for (int i = 0; i < childArrayCount; i++) { childArray[i] = BitConverter.ToUInt32(buffer, 4 * i); } //curve data stores animated properties on the node curves = model.ReadAnimationCurves(mdlStream, curveKeyArrayCount, curveKeyArrayOffset, curveDataArrayCount, curveDataArrayOffset, this); children = new Node[childArrayCount]; for (int i = 0; i < childArrayCount; i++) { mdlStream.Position = model.modelDataOffset + childArray[i]; children[i] = model.CreateNode(mdlStream, mdxStream, this); } mdlStream.Position = pos; }
public SaberNode(Stream mdlStream, Stream mdxStream, Type nodeType, AuroraModel model) : base(mdlStream, mdxStream, nodeType, model) { byte[] buffer = new byte[12]; mdlStream.Read(buffer, 0, 12); uint offsetVertsCoords2 = BitConverter.ToUInt32(buffer, 0); uint offsetTexCoords = BitConverter.ToUInt32(buffer, 4); uint offsetSaberData = BitConverter.ToUInt32(buffer, 8); mdlStream.Position = model.modelDataOffset + vertexCoordsOffset; buffer = new byte[Vertices.Length * 12]; mdlStream.Read(buffer, 0, buffer.Length); for (int i = 0; i < Vertices.Length; i++) { Vertices[i] = new Vector3(BitConverter.ToSingle(buffer, 0), BitConverter.ToSingle(buffer, 8), BitConverter.ToSingle(buffer, 4)); } }
public SkinnedMeshNode(Stream mdlStream, Stream mdxStream, Type nodeType, AuroraModel model) : base(mdlStream, mdxStream, nodeType, model) { byte[] buffer = new byte[102]; mdlStream.Read(buffer, 0, 102); uint weightsOffset = BitConverter.ToUInt32(buffer, 0); uint weightsCount = BitConverter.ToUInt32(buffer, 4); uint weightsCapacity = BitConverter.ToUInt32(buffer, 8); uint mdxVertexStructOffsetBoneWeights = BitConverter.ToUInt32(buffer, 12); uint mdxVertexStructOffsetBoneMappingID = BitConverter.ToUInt32(buffer, 16); uint boneMappingOffset = BitConverter.ToUInt32(buffer, 20); uint boneMappingCount = BitConverter.ToUInt32(buffer, 24); uint boneQuatsOffset = BitConverter.ToUInt32(buffer, 28); uint boneQuatsCount = BitConverter.ToUInt32(buffer, 32); uint boneQuatsCapacity = BitConverter.ToUInt32(buffer, 36); uint boneVertsOffset = BitConverter.ToUInt32(buffer, 40); uint boneVertsCount = BitConverter.ToUInt32(buffer, 44); uint boneVertsCapacity = BitConverter.ToUInt32(buffer, 48); uint boneConstsOffset = BitConverter.ToUInt32(buffer, 52); uint boneConstsCount = BitConverter.ToUInt32(buffer, 56); uint boneConstsCapacity = BitConverter.ToUInt32(buffer, 60); boneToNodeMap = new short[16]; for (int i = 0; i < boneToNodeMap.Length; i++) { boneToNodeMap[i] = BitConverter.ToInt16(buffer, 64 + (i * 2)); } //int spare = BitConverter.ToInt32(buffer, 98); // read the bone weights for each vertex mdxStream.Position = mdxNodeDataOffset + mdxVertexStructOffsetBoneWeights; buffer = new byte[mdxDataSize * Vertices.Length]; mdxStream.Read(buffer, 0, (int)mdxDataSize * Vertices.Length); Weights = new BoneWeight[Vertices.Length]; for (int i = 0, offset = 0; i < Vertices.Length; i++, offset += (int)mdxDataSize) { Weights[i] = new BoneWeight { weight0 = BitConverter.ToSingle(buffer, offset + 0), weight1 = BitConverter.ToSingle(buffer, offset + 4), weight2 = BitConverter.ToSingle(buffer, offset + 8), weight3 = BitConverter.ToSingle(buffer, offset + 12), boneIndex0 = (int)BitConverter.ToSingle(buffer, offset + 16), boneIndex1 = (int)BitConverter.ToSingle(buffer, offset + 20), boneIndex2 = (int)BitConverter.ToSingle(buffer, offset + 24), boneIndex3 = (int)BitConverter.ToSingle(buffer, offset + 28), }; } // node to bone index maps each index in the node list to an index in this skin's bone list, or -1 mdlStream.Position = model.modelDataOffset + boneMappingOffset; buffer = new byte[boneMappingCount * 4]; mdlStream.Read(buffer, 0, (int)boneMappingCount * 4); nodeToBoneMap = new float[boneMappingCount]; for (int j = 0; j < boneMappingCount; j++) { nodeToBoneMap[j] = BitConverter.ToSingle(buffer, j * 4); } // read the bone quaternions mdlStream.Position = model.modelDataOffset + boneQuatsOffset; buffer = new byte[boneQuatsCount * 16]; mdlStream.Read(buffer, 0, (int)boneQuatsCount * 16); Quaternion[] boneQuats = new Quaternion[boneQuatsCount]; for (int j = 0, offset = 0; j < boneQuatsCount; j++, offset += 16) { boneQuats[j] = new Quaternion(BitConverter.ToSingle(buffer, offset + 4), BitConverter.ToSingle(buffer, offset + 8), BitConverter.ToSingle(buffer, offset + 12), BitConverter.ToSingle(buffer, offset + 0)); boneQuats[j].Normalize(); } // read the bone vertices mdlStream.Position = model.modelDataOffset + boneVertsOffset; buffer = new byte[boneVertsCount * 12]; mdlStream.Read(buffer, 0, (int)boneVertsCount * 12); Vector3[] boneVerts = new Vector3[boneVertsCount]; for (int j = 0, offset = 0; j < boneQuatsCount; j++, offset += 12) { boneVerts[j] = new Vector3(BitConverter.ToSingle(buffer, offset + 0), BitConverter.ToSingle(buffer, offset + 8), BitConverter.ToSingle(buffer, offset + 4)); } // read the bone consts mdlStream.Position = model.modelDataOffset + boneConstsOffset; buffer = new byte[boneConstsCount * 12]; mdlStream.Read(buffer, 0, (int)boneConstsCount * 12); ushort[] boneConsts = new ushort[boneConstsCount]; for (int j = 0; j < boneConstsCount; j++) { boneConsts[j] = BitConverter.ToUInt16(buffer, j * 2); } }
public static GameObject LoadModel(string resref) { Stream mdl = GetStream(resref, ResourceType.MDL), mdx = GetStream(resref, ResourceType.MDX); if (mdl == null || mdx == null) { Debug.Log("Missing model: " + resref); return(new GameObject(resref)); } AuroraModel auroraModel = new AuroraModel(mdl, mdx, targetGame); GameObject CreateObject(AuroraModel.Node node, Transform parent) { GameObject go = new GameObject(node.name); if (parent) { go.transform.SetParent(parent, false); } go.transform.localPosition = node.position; go.transform.localRotation = node.rotation; if (node is AuroraModel.MeshNode) { AuroraModel.MeshNode auroraMesh = (AuroraModel.MeshNode)node; Mesh mesh = auroraMesh.CreateUnityMesh(); //if (auroraMesh.isWalkmesh) { MeshCollider col = go.AddComponent <MeshCollider>(); col.cookingOptions = MeshColliderCookingOptions.None; col.sharedMesh = mesh; //} if (node is AuroraModel.SkinnedMeshNode) { SkinnedMeshRenderer renderer = go.AddComponent <SkinnedMeshRenderer>(); renderer.material = LoadMaterial(auroraMesh.DiffuseMap, auroraMesh.LightMap); renderer.sharedMesh = mesh; } else { go.AddComponent <MeshFilter>().mesh = mesh; MeshRenderer renderer = go.AddComponent <MeshRenderer>(); renderer.material = LoadMaterial(auroraMesh.DiffuseMap, auroraMesh.LightMap); //meshes with a null texture should be invisible if (auroraMesh.DiffuseMap == "NULL") { renderer.enabled = false; } } } for (int i = 0; i < node.children.Length; i++) { CreateObject(node.children[i], go.transform); } node.transform = go.transform; return(go); } GameObject model = CreateObject(auroraModel.rootNode, null); void SkinObject(AuroraModel.Node node) { if (node is AuroraModel.SkinnedMeshNode) { SkinnedMeshRenderer renderer = node.transform.GetComponent <SkinnedMeshRenderer>(); Mesh mesh = renderer.sharedMesh; short[] boneMapping = ((AuroraModel.SkinnedMeshNode)node).boneToNodeMap; List <Transform> boneTransforms = new List <Transform>(); List <Matrix4x4> bindPoses = new List <Matrix4x4>(); for (int i = 0; i < boneMapping.Length; i++) { if (boneMapping[i] >= 0 && boneMapping[i] < auroraModel.nodes.Count) { Transform t = auroraModel.nodes[boneMapping[i]].transform; boneTransforms.Add(t); bindPoses.Add(t.worldToLocalMatrix * node.transform.localToWorldMatrix); } } renderer.bones = boneTransforms.ToArray(); mesh.bindposes = bindPoses.ToArray(); } for (int i = 0; i < node.children.Length; i++) { SkinObject(node.children[i]); } } Animation animComponent = model.AddComponent <Animation>(); AnimationClip[] clips = auroraModel.GetUnityAnimationClips(); //TODO: check if animation is looping for (int i = 0; i < clips.Length; i++) { animComponent.AddClip(clips[i], clips[i].name); } SkinObject(auroraModel.rootNode); return(model); }
public MeshNode(Stream mdlStream, Stream mdxStream, Type nodeType, AuroraModel model) : base(mdlStream, mdxStream, nodeType, model) { //TODO: need to properly read walkmesh data if ((nodeType & Node.Type.AABB) == Node.Type.AABB) { isWalkmesh = true; } byte[] buffer = new byte[88]; mdlStream.Read(buffer, 0, 88); uint facesOffset = BitConverter.ToUInt32(buffer, 8); uint facesCount = BitConverter.ToUInt32(buffer, 12); uint facesCapacity = BitConverter.ToUInt32(buffer, 16); Vector3 minBounds = new Vector3(BitConverter.ToSingle(buffer, 20), BitConverter.ToSingle(buffer, 24), BitConverter.ToSingle(buffer, 28)); Vector3 maxBounds = new Vector3(BitConverter.ToSingle(buffer, 32), BitConverter.ToSingle(buffer, 36), BitConverter.ToSingle(buffer, 40)); radius = BitConverter.ToSingle(buffer, 44); pointsAverage = new Vector3(BitConverter.ToSingle(buffer, 48), BitConverter.ToSingle(buffer, 52), BitConverter.ToSingle(buffer, 56)); diffuse = new Color(BitConverter.ToSingle(buffer, 60), BitConverter.ToSingle(buffer, 64), BitConverter.ToSingle(buffer, 68)); ambient = new Color(BitConverter.ToSingle(buffer, 72), BitConverter.ToSingle(buffer, 76), BitConverter.ToSingle(buffer, 80)); transparencyHint = BitConverter.ToUInt32(buffer, 84); buffer = new byte[88]; mdlStream.Read(buffer, 0, 88); DiffuseMap = Encoding.UTF8.GetString(buffer, 0, 32).Split('\0')[0]; LightMap = Encoding.UTF8.GetString(buffer, 32, 32).Split('\0')[0]; texMap3 = Encoding.UTF8.GetString(buffer, 64, 12).Split('\0')[0]; texMap4 = Encoding.UTF8.GetString(buffer, 76, 12).Split('\0')[0]; buffer = new byte[132]; mdlStream.Read(buffer, 0, 132); uint indexArrayOffset = BitConverter.ToUInt32(buffer, 0); uint indexArrayCount = BitConverter.ToUInt32(buffer, 4); uint indexArrayCapacity = BitConverter.ToUInt32(buffer, 8); //the face data array contains a list of offsets to arrays which contain face data for this mesh, should never be more than one uint faceDataOffsetsOffset = BitConverter.ToUInt32(buffer, 12); uint faceDataOffsetsCount = BitConverter.ToUInt32(buffer, 16); uint faceDataOffsetsCapacity = BitConverter.ToUInt32(buffer, 20); //warn if there's more than one list of face data if (faceDataOffsetsCount > 1) { Debug.LogWarning("faceDataOffsetsCount > 1, this mesh seems to have multiple face arrays."); } //regardless, we'll go to the start of the face data array and select the first offset, assuming that the first offset in the array points to the face data we want uint[] faceDataOffsets = new uint[faceDataOffsetsCount]; long pos = mdlStream.Position; mdlStream.Position = model.modelDataOffset + faceDataOffsetsOffset; mdlStream.Read(buffer, 0, 4 * (int)faceDataOffsetsCount); mdlStream.Position = pos; for (int i = 0; i < faceDataOffsetsCount; i++) { faceDataOffsets[i] = BitConverter.ToUInt32(buffer, i * 4); } saberBytes = new byte[] { buffer[48], buffer[49], buffer[50], buffer[51], buffer[52], buffer[53], buffer[54], buffer[55] }; nAnimateUV = BitConverter.ToUInt32(buffer, 56); fUVDirX = BitConverter.ToSingle(buffer, 60); fUVDirY = BitConverter.ToSingle(buffer, 64); fUVJitter = BitConverter.ToSingle(buffer, 68); fUVJitterSpeed = BitConverter.ToSingle(buffer, 72); mdxDataSize = BitConverter.ToUInt32(buffer, 76); mdxDataBitmap = BitConverter.ToUInt32(buffer, 80); uint mdxVertexVertexOffset = BitConverter.ToUInt32(buffer, 84); uint mdxVertexNormalsOffset = BitConverter.ToUInt32(buffer, 88); uint mdxVertexNormalsUnused = BitConverter.ToUInt32(buffer, 92); int[] uvOffsets = new int[] { BitConverter.ToInt32(buffer, 96), BitConverter.ToInt32(buffer, 100), BitConverter.ToInt32(buffer, 104), BitConverter.ToInt32(buffer, 108), }; int[] offsetToMdxTangent = new int[] { BitConverter.ToInt32(buffer, 112), BitConverter.ToInt32(buffer, 116), BitConverter.ToInt32(buffer, 120), BitConverter.ToInt32(buffer, 124), }; ushort vertexCount = BitConverter.ToUInt16(buffer, 128); ushort textureCount = BitConverter.ToUInt16(buffer, 130); int hasLightmap = mdlStream.ReadByte(); int rotateTex = mdlStream.ReadByte(); int backgroundGeom = mdlStream.ReadByte(); int flagShadow = mdlStream.ReadByte(); int beaming = mdlStream.ReadByte(); int flagRender = mdlStream.ReadByte(); if (model.importFrom == Game.TSL) { int dirtEnabled = mdlStream.ReadByte(); int tslPadding1 = mdlStream.ReadByte(); mdlStream.Read(buffer, 0, 4); ushort dirtTex = BitConverter.ToUInt16(buffer, 0); ushort dirtCoordSpace = BitConverter.ToUInt16(buffer, 2); int hideInHolograms = mdlStream.ReadByte(); int tslPadding2 = mdlStream.ReadByte(); } buffer = new byte[18]; mdlStream.Read(buffer, 0, 18); float totalArea = BitConverter.ToSingle(buffer, 2); mdxNodeDataOffset = BitConverter.ToUInt32(buffer, 10); vertexCoordsOffset = BitConverter.ToUInt32(buffer, 14); Triangles = new int[facesCount * 3]; //3 vertices per face Vertices = new Vector3[vertexCount]; Normals = new Vector3[vertexCount]; Vector2[][] uvs = new Vector2[4][]; for (int t = 0; t < textureCount; t++) { uvs[t] = new Vector2[vertexCount]; } if (faceDataOffsetsCount == 0 || vertexCount == 0 || facesCount == 0) { return; } long endPos = mdlStream.Position; buffer = new byte[mdxDataSize * vertexCount]; mdxStream.Position = mdxNodeDataOffset; mdxStream.Read(buffer, 0, (int)mdxDataSize * vertexCount); for (int i = 0, offset = 0; i < vertexCount; i++, offset += (int)mdxDataSize) { //flip the y and z co-ordinates Vertices[i] = new Vector3(BitConverter.ToSingle(buffer, offset + 0), BitConverter.ToSingle(buffer, offset + 8), BitConverter.ToSingle(buffer, offset + 4)); Normals[i] = new Vector3(BitConverter.ToSingle(buffer, offset + 12), BitConverter.ToSingle(buffer, offset + 20), BitConverter.ToSingle(buffer, offset + 16)) * -1; //read the uvs for each of the four (potential) texture maps, for (int t = 0, uvOffset = 24; t < textureCount; t++, uvOffset += 8) { uvs[t][i] = new Vector2(BitConverter.ToSingle(buffer, offset + uvOffset + 0), BitConverter.ToSingle(buffer, offset + uvOffset + 4)); } } buffer = new byte[6 * facesCount]; //6 bytes (3 shorts) per face mdlStream.Position = model.modelDataOffset + faceDataOffsets[0]; mdlStream.Read(buffer, 0, 6 * (int)facesCount); if (textureCount != 0) { for (int i = 0; i < facesCount; i++) { //flip faces 1 and 2 to keep the normals pointing out Triangles[(i * 3) + 0] = BitConverter.ToUInt16(buffer, (i * 6) + 0); Triangles[(i * 3) + 1] = BitConverter.ToUInt16(buffer, (i * 6) + 4); Triangles[(i * 3) + 2] = BitConverter.ToUInt16(buffer, (i * 6) + 2); } } if (uvs[0] != null) { DiffuseUVs = uvs[0]; } if (uvs[1] != null) { LightmapUVs = uvs[1]; } mdlStream.Position = endPos; }