public void LoadFrom_p3s_c4b_t2s(DataStream_p3s_c4b_t2s p3s_c4b_t2sList) { mesh = new Mesh(nCount); foreach (DataStream_p3s_c4b_t2s_Elem p3s_c4b_t2s in p3s_c4b_t2sList.p3s_c4b_t2sElem) { DataStream_Positions_Elem position = new DataStream_Positions_Elem(); for (int i = 0; i < 3; i++) { Half halfEl = new Half(); halfEl.value = p3s_c4b_t2s.pos[i]; position.pos[i] = HalfHelper.HalfToSingle(halfEl); } mesh.positions.position.Add(position); DataStream_Colors_Elem color = new DataStream_Colors_Elem(); for (int i = 0; i < 4; i++) { color.rgba[i] = p3s_c4b_t2s.bgra[i]; } mesh.colors.color.Add(color); DataStream_Texcoords_Elem texoord = new DataStream_Texcoords_Elem(); for (int i = 0; i < 2; i++) { Half halfEl = new Half(); halfEl.value = p3s_c4b_t2s.uv[i]; texoord.uv[i] = HalfHelper.HalfToSingle(halfEl); } mesh.texcoords.texcoord.Add(texoord); } }
public ONNXTensor(TensorProto onnxTensor) { // read shape var onnxShape = onnxTensor.Dims.ToArray(); var shape = ONNXLayout.ConvertShapeToBarracuda(onnxShape, onnxLayout: "?"); // read data float[] data; if ((onnxTensor.RawData != null) && (!onnxTensor.RawData.IsEmpty)) { var byteArray = new byte[onnxTensor.RawData.Length]; onnxTensor.RawData.CopyTo(byteArray, 0); // Float32 if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Float) { data = new float[shape.length]; Debug.Assert((sizeof(float) * shape.length) == onnxTensor.RawData.Length); Buffer.BlockCopy(byteArray, 0, data, 0, byteArray.Length); } // Float16 else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Float16) { var typedData = new UInt16[shape.length]; Debug.Assert((sizeof(UInt16) * shape.length) == onnxTensor.RawData.Length); Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); data = typedData.Select(x => HalfHelper.HalfToSingle(x)).ToArray(); } // Int32 else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Int32) { var typedData = new int[shape.length]; Debug.Assert((sizeof(int) * shape.length) == onnxTensor.RawData.Length); Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); data = typedData.Select(x => (float)x).ToArray(); } // Int64 else if (onnxTensor.DataType == (int)TensorProto.Types.DataType.Int64) { var typedData = new long[shape.length]; Debug.Assert((sizeof(long) * shape.length) == onnxTensor.RawData.Length); Buffer.BlockCopy(byteArray, 0, typedData, 0, byteArray.Length); data = typedData.Select(x => (float)x).ToArray(); } else { throw new OnnxLayerImportException($"Tensor data type {(TensorProto.Types.DataType)onnxTensor.DataType} is not supported."); } } // Float32 else if ((onnxTensor.FloatData != null) && (onnxTensor.FloatData.Count != 0)) { Debug.Assert(shape.length == onnxTensor.FloatData.Count); data = new float[shape.length]; onnxTensor.FloatData.CopyTo(data, 0); } // Int32 else if ((onnxTensor.Int32Data != null) && (onnxTensor.Int32Data.Count != 0)) { Debug.Assert(shape.length == onnxTensor.Int32Data.Count); data = onnxTensor.Int32Data.Select(x => (float)x).ToArray(); } // Int64 else if ((onnxTensor.Int64Data != null) && (onnxTensor.Int64Data.Count != 0)) { Debug.Assert(shape.length == onnxTensor.Int64Data.Count); data = onnxTensor.Int64Data.Select(x => (float)x).ToArray(); } else { throw new OnnxLayerImportException("Could not read tensor data for constant tensor."); } m_Data = new Tensor(shape, new SharedArrayTensorData(data)); m_Shape = onnxShape; }
/// <summary> /// Parses the MDL file to obtain model information /// </summary> /// <param name="selectedItem">The currently selected item</param> /// <param name="selectedRace">The currently selected race</param> /// <param name="selectedBody">The currently selected body</param> /// <param name="selectedPart">The currently selected part</param> /// <param name="selectedCategory">The items category </param> public MDL(ItemData selectedItem, string selectedCategory, string selectedRace, string selectedBody, string selectedPart) { string itemType = Helper.GetCategoryType(selectedCategory); string MDLFolder = ""; if (itemType.Equals("weapon") || itemType.Equals("food")) { if (selectedPart.Equals("Secondary")) { MDLFolder = string.Format(Strings.WeapMDLFolder, selectedItem.SecondaryModelID, selectedItem.SecondaryModelBody); MDLFile = string.Format(Strings.WeapMDLFile, selectedItem.SecondaryModelID, selectedItem.SecondaryModelBody); } else { MDLFolder = string.Format(Strings.WeapMDLFolder, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); MDLFile = string.Format(Strings.WeapMDLFile, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); } } else if (itemType.Equals("accessory")) { MDLFolder = string.Format(Strings.AccMDLFolder, selectedItem.PrimaryModelID); MDLFile = string.Format(Strings.AccMDLFile, selectedRace, selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } else if (itemType.Equals("character")) { if (selectedItem.ItemName.Equals(Strings.Body)) { MDLFolder = string.Format(Strings.BodyMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.BodyMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Face)) { MDLFolder = string.Format(Strings.FaceMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.FaceMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Hair)) { MDLFolder = string.Format(Strings.HairMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.HairMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Tail)) { MDLFolder = string.Format(Strings.TailMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.TailMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } } else if (itemType.Equals("monster")) { bool isDemiHuman = false; if (selectedItem.PrimaryMTRLFolder != null) { isDemiHuman = selectedItem.PrimaryMTRLFolder.Contains("demihuman"); } string ID = ""; string body = ""; if (selectedCategory.Equals(Strings.Pets)) { int part = 1; if (selectedItem.ItemName.Equals(Strings.Selene) || selectedItem.ItemName.Equals(Strings.Bishop_Autoturret)) { part = 2; } ID = Info.petID[selectedItem.ItemName]; body = part.ToString().PadLeft(4, '0'); } else { ID = selectedItem.PrimaryModelID.PadLeft(4, '0'); body = selectedItem.PrimaryModelBody; } if (isDemiHuman) { MDLFolder = string.Format(Strings.DemiMDLFolder, ID, body); MDLFile = string.Format(Strings.DemiMDLFile, ID, body, selectedPart); } else { MDLFolder = string.Format(Strings.MonsterMDLFolder, ID, body); MDLFile = string.Format(Strings.MonsterMDLFile, ID, body); } } else { MDLFolder = string.Format(Strings.EquipMDLFolder, selectedItem.PrimaryModelID); if (selectedPart.Equals("-")) { MDLFile = string.Format(Strings.EquipMDLFile, selectedRace, selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } else { MDLFile = string.Format(Strings.EquipMDLFile, selectedRace, selectedItem.PrimaryModelID, selectedPart); } } fullPath = MDLFolder + "/" + MDLFile; int offset = Helper.GetDataOffset(FFCRC.GetHash(MDLFolder), FFCRC.GetHash(MDLFile), Strings.ItemsDat); if (offset == 0) { if (itemType.Equals("weapon")) { if (selectedPart.Equals("Secondary")) { MDLFolder = string.Format(Strings.EquipMDLFolder, selectedItem.SecondaryModelID); MDLFile = string.Format(Strings.EquipMDLFile, "0101", selectedItem.SecondaryModelID, Info.slotAbr[Strings.Hands]); offset = Helper.GetDataOffset(FFCRC.GetHash(MDLFolder), FFCRC.GetHash(MDLFile), Strings.ItemsDat); } } } int datNum = ((offset / 8) & 0x000f) / 2; var MDLDatData = Helper.GetType3DecompressedData(offset, datNum, Strings.ItemsDat); using (BinaryReader br = new BinaryReader(new MemoryStream(MDLDatData.Item1))) { // The size of the header + (size of the mesh information block (136 bytes) * the number of meshes) + padding br.BaseStream.Seek(64 + 136 * MDLDatData.Item2 + 4, SeekOrigin.Begin); var modelStringCount = br.ReadInt32(); var stringBlockSize = br.ReadInt32(); var stringBlock = br.ReadBytes(stringBlockSize); var unknown = br.ReadBytes(4); var totalMeshCount = br.ReadInt16(); var attributeStringCount = br.ReadInt16(); var meshPartsCount = br.ReadInt16(); var materialStringCount = br.ReadInt16(); var boneStringCount = br.ReadInt16(); var boneListCount = br.ReadInt16(); var unknown1 = br.ReadInt16(); var unknown2 = br.ReadInt16(); var unknown3 = br.ReadInt16(); var unknown4 = br.ReadInt16(); var unknown5 = br.ReadInt16(); var unknown6 = br.ReadInt16(); br.ReadBytes(10); var unknown7 = br.ReadInt16(); br.ReadBytes(16); using (BinaryReader br1 = new BinaryReader(new MemoryStream(stringBlock))) { br1.BaseStream.Seek(0, SeekOrigin.Begin); for (int i = 0; i < attributeStringCount; i++) { while (br1.ReadByte() != 0) { //extract each atribute string here } } for (int i = 0; i < boneStringCount; i++) { byte b; List <byte> boneName = new List <byte>(); while ((b = br1.ReadByte()) != 0) { boneName.Add(b); } string bone = Encoding.ASCII.GetString(boneName.ToArray()); bone = bone.Replace("\0", ""); boneStrings.Add(bone); } for (int i = 0; i < materialStringCount; i++) { byte b; List <byte> name = new List <byte>(); while ((b = br1.ReadByte()) != 0) { name.Add(b); } string material = Encoding.ASCII.GetString(name.ToArray()); material = material.Replace("\0", ""); materialStrings.Add(material); } } br.ReadBytes(32 * unknown5); for (int i = 0; i < 3; i++) { LevelOfDetail LoD = new LevelOfDetail(); LoD.MeshOffset = br.ReadInt16(); LoD.MeshCount = br.ReadInt16(); br.ReadBytes(40); LoD.VertexDataSize = br.ReadInt32(); LoD.IndexDataSize = br.ReadInt32(); LoD.VertexOffset = br.ReadInt32(); LoD.IndexOffset = br.ReadInt32(); modelData.LoD.Add(LoD); } var savePos = br.BaseStream.Position; for (int i = 0; i < modelData.LoD.Count; i++) { List <MeshDataInfo> meshInfoList = new List <MeshDataInfo>(); for (int j = 0; j < modelData.LoD[i].MeshCount; j++) { modelData.LoD[i].MeshList.Add(new Mesh()); meshInfoList.Clear(); br.BaseStream.Seek((i * 136) + 68, SeekOrigin.Begin); var dataBlockNum = br.ReadByte(); while (dataBlockNum != 255) { MeshDataInfo meshInfo = new MeshDataInfo() { VertexDataBlock = dataBlockNum, Offset = br.ReadByte(), DataType = br.ReadByte(), UseType = br.ReadByte() }; meshInfoList.Add(meshInfo); br.ReadBytes(4); dataBlockNum = br.ReadByte(); } modelData.LoD[i].MeshList[j].MeshDataInfoList = meshInfoList.ToArray(); } } br.BaseStream.Seek(savePos, SeekOrigin.Begin); for (int x = 0; x < modelData.LoD.Count; x++) { for (int i = 0; i < modelData.LoD[x].MeshCount; i++) { MeshInfo meshInfo = new MeshInfo() { VertexCount = br.ReadInt32(), IndexCount = br.ReadInt32(), MaterialNum = br.ReadInt16(), MeshPartOffset = br.ReadInt16(), MeshPartCount = br.ReadInt16(), BoneListIndex = br.ReadInt16(), IndexDataOffset = br.ReadInt32() }; for (int j = 0; j < 3; j++) { meshInfo.VertexDataOffsets.Add(br.ReadInt32()); } for (int k = 0; k < 3; k++) { meshInfo.VertexSizes.Add(br.ReadByte()); } meshInfo.VertexDataBlockCount = br.ReadByte(); modelData.LoD[x].MeshList[i].MeshInfo = meshInfo; } } br.ReadBytes(attributeStringCount * 4); br.ReadBytes(unknown6 * 20); for (int i = 0; i < modelData.LoD.Count; i++) { foreach (var mesh in modelData.LoD[i].MeshList) { for (int j = 0; j < mesh.MeshInfo.MeshPartCount; j++) { MeshPart meshPart = new MeshPart() { IndexOffset = br.ReadInt32(), IndexCount = br.ReadInt32(), Attributes = br.ReadInt32(), BoneOffset = br.ReadInt16(), BoneCount = br.ReadInt16() }; mesh.MeshPartList.Add(meshPart); } } } br.ReadBytes(unknown7 * 12); br.ReadBytes(materialStringCount * 4); br.ReadBytes(boneStringCount * 4); for (int i = 0; i < boneListCount; i++) { Bones bones = new Bones(); for (int j = 0; j < 64; j++) { bones.BoneData.Add(br.ReadInt16()); } bones.BoneCount = br.ReadInt32(); modelData.BoneSet.Add(bones); } //br.ReadBytes(unknown1 * 16); Dictionary <int, int> indexMin = new Dictionary <int, int>(); Dictionary <int, List <int> > extraIndices = new Dictionary <int, List <int> >(); List <ExtraIndex> indexCounts = new List <ExtraIndex>(); var pCount = 0; var pCount1 = 0; var pCount2 = 0; if (unknown1 > 0) { for (int i = 0; i < unknown1; i++) { //not sure br.ReadBytes(4); //LoD[0] Extra Data Index var p1 = br.ReadUInt16(); //LoD[1] Extra Data Index var p2 = br.ReadUInt16(); //LoD[2] Extra Data Index var p3 = br.ReadUInt16(); //LoD[0] Extra Data Part Count var p1n = br.ReadUInt16(); pCount += p1n; //LoD[1] Extra Data Part Count var p2n = br.ReadUInt16(); pCount1 += p2n; //LoD[2] Extra Data Part Count var p3n = br.ReadUInt16(); pCount2 += p3n; } } Dictionary <int, int> indexLoc = new Dictionary <int, int>(); if (unknown1 > 0) { for (int i = 0; i < modelData.LoD[0].MeshCount; i++) { var ido = modelData.LoD[0].MeshList[i].MeshInfo.IndexDataOffset; indexLoc.Add(ido, i); } } List <int> maskCounts = new List <int>(); Dictionary <int, int> totalExtraCounts = new Dictionary <int, int>(); if (unknown2 > 0) { for (int i = 0; i < pCount; i++) { //Index Offset Start var m1 = br.ReadInt32(); var iLoc = 0; if (indexLoc.ContainsKey(m1)) { iLoc = indexLoc[m1]; } //index count var mCount = br.ReadInt32(); //index offset in unk3 var mOffset = br.ReadInt32(); indexCounts.Add(new ExtraIndex() { IndexLocation = iLoc, IndexCount = mCount }); maskCounts.Add(mCount); } br.ReadBytes((pCount1 + pCount2) * 12); } int totalLoD0MaskCount = 0; if (unknown2 > 0) { for (int i = 0; i < pCount; i++) { totalLoD0MaskCount += maskCounts[i]; } } if (unknown3 > 0) { var unk3Remainder = (unknown3 * 4) - (totalLoD0MaskCount * 4); foreach (var ic in indexCounts) { HashSet <int> mIndexList = new HashSet <int>(); for (int i = 0; i < ic.IndexCount; i++) { //index its replacing? attatched to? br.ReadBytes(2); //extra index following last equipment index var mIndex = br.ReadInt16(); mIndexList.Add(mIndex); if (extraIndices.ContainsKey(ic.IndexLocation)) { extraIndices[ic.IndexLocation].Add(mIndex); } else { extraIndices.Add(ic.IndexLocation, new List <int>() { mIndex }); } } if (totalExtraCounts.ContainsKey(ic.IndexLocation)) { totalExtraCounts[ic.IndexLocation] += mIndexList.Count; } else { totalExtraCounts.Add(ic.IndexLocation, mIndexList.Count); } } //the rest of unk3 br.ReadBytes(unk3Remainder); } if (unknown3 > 0) { foreach (var ei in extraIndices) { indexMin.Add(ei.Key, ei.Value.Min()); } extraIndexData.indexCounts = indexCounts; extraIndexData.indexMin = indexMin; extraIndexData.totalExtraCounts = totalExtraCounts; extraIndexData.extraIndices = extraIndices; modelData.ExtraData = extraIndexData; } //br.ReadBytes(unknown3 * 4); var boneIndexSize = br.ReadInt32(); for (int i = 0; i < boneIndexSize / 2; i++) { modelData.BoneIndicies.Add(br.ReadInt16()); } int padding = br.ReadByte(); br.ReadBytes(padding); for (int i = 0; i < 4; i++) { ModelMaterial.BoundingBox boundingBox = new ModelMaterial.BoundingBox(); for (int j = 0; j < 4; j++) { boundingBox.PointA.Add(br.ReadSingle()); } for (int k = 0; k < 4; k++) { boundingBox.PointB.Add(br.ReadSingle()); } modelData.BoundingBoxes.Add(boundingBox); } //float4x4 for (int i = 0; i < boneStringCount; i++) { boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); boneTransforms.Add(br.ReadSingle()); } for (int i = 0; i < 3; i++) { for (int j = 0; j < modelData.LoD[i].MeshCount; j++) { Mesh mesh = modelData.LoD[i].MeshList[j]; for (int k = 0; k < mesh.MeshInfo.VertexDataBlockCount; k++) { br.BaseStream.Seek(modelData.LoD[i].VertexOffset + mesh.MeshInfo.VertexDataOffsets[k], SeekOrigin.Begin); mesh.MeshVertexData.Add(br.ReadBytes(mesh.MeshInfo.VertexSizes[k] * mesh.MeshInfo.VertexCount)); } br.BaseStream.Seek(modelData.LoD[i].IndexOffset + (mesh.MeshInfo.IndexDataOffset * 2), SeekOrigin.Begin); mesh.IndexData = br.ReadBytes(2 * mesh.MeshInfo.IndexCount); } } int vertex = 0, coordinates = 0, normals = 0, tangents = 0, colors = 0, blendWeights = 0, blendIndices = 0; for (int i = 0; i < modelData.LoD[0].MeshCount; i++) { objBytes.Clear(); var vertexList = new Vector3Collection(); var texCoordList = new Vector2Collection(); var texCoordList2 = new Vector2Collection(); var normalList = new Vector3Collection(); var tangentList = new Vector3Collection(); var colorsList = new Color4Collection(); var indexList = new IntCollection(); var blendWeightList = new List <float>(); var blendWeightList2 = new List <float[]>(); var blendIndicesList = new List <int>(); var blendIndicesList2 = new List <int[]>(); var weightCounts = new List <int>(); Mesh mesh = modelData.LoD[0].MeshList[i]; MeshDataInfo[] meshDataInfoList = mesh.MeshDataInfoList; int c = 0; foreach (var meshDataInfo in meshDataInfoList) { if (meshDataInfo.UseType == 0) { vertex = c; } else if (meshDataInfo.UseType == 1) { blendWeights = c; } else if (meshDataInfo.UseType == 2) { blendIndices = c; } else if (meshDataInfo.UseType == 3) { normals = c; } else if (meshDataInfo.UseType == 4) { coordinates = c; } else if (meshDataInfo.UseType == 6) { tangents = c; } else if (meshDataInfo.UseType == 7) { colors = c; } c++; } /* * ----------------- * Vertex * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[vertex].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[vertex].VertexDataBlock] + meshDataInfoList[vertex].Offset, SeekOrigin.Begin); Vector3 vVector = new Vector3(); if (meshDataInfoList[vertex].DataType == 13 || meshDataInfoList[vertex].DataType == 14) { System.Half h1 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h2 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h3 = System.Half.ToHalf((ushort)br1.ReadInt16()); float x = HalfHelper.HalfToSingle(h1); float y = HalfHelper.HalfToSingle(h2); float z = HalfHelper.HalfToSingle(h3); vVector = new Vector3(x, y, z); objBytes.Add("v " + x.ToString("N5") + " " + y.ToString("N5") + " " + z.ToString("N5") + " "); } else if (meshDataInfoList[vertex].DataType == 2) { var x = BitConverter.ToSingle(br1.ReadBytes(4), 0); var y = BitConverter.ToSingle(br1.ReadBytes(4), 0); var z = BitConverter.ToSingle(br1.ReadBytes(4), 0); vVector = new Vector3(x, y, z); objBytes.Add("v " + x.ToString("N5") + " " + y.ToString("N5") + " " + z.ToString("N5") + " "); } vertexList.Add(vVector); } } /* * ----------------- * Blend Weight * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[blendWeights].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[blendWeights].VertexDataBlock] + meshDataInfoList[blendWeights].Offset, SeekOrigin.Begin); float x = br1.ReadByte() / 255.0f; float y = br1.ReadByte() / 255.0f; float z = br1.ReadByte() / 255.0f; float w = br1.ReadByte() / 255.0f; int count = 0; if (x != 0) { blendWeightList.Add(x); count++; if (y != 0) { blendWeightList.Add(y); count++; if (z != 0) { blendWeightList.Add(z); count++; if (w != 0) { blendWeightList.Add(w); count++; } } } } if (count == 1) { blendWeightList2.Add(new float[] { x }); } else if (count == 2) { blendWeightList2.Add(new float[] { x, y }); } else if (count == 3) { blendWeightList2.Add(new float[] { x, y, z }); } else if (count == 4) { blendWeightList2.Add(new float[] { x, y, z, w }); } weightCounts.Add(count); } } /* * ----------------- * Blend Index * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[blendIndices].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[blendIndices].VertexDataBlock] + meshDataInfoList[blendIndices].Offset, SeekOrigin.Begin); int x = br1.ReadByte(); int y = br1.ReadByte(); int z = br1.ReadByte(); int w = br1.ReadByte(); if (weightCounts[j] == 1) { blendIndicesList.Add(x); blendIndicesList2.Add(new int[] { x }); } else if (weightCounts[j] == 2) { blendIndicesList.Add(x); blendIndicesList.Add(y); blendIndicesList2.Add(new int[] { x, y }); } else if (weightCounts[j] == 3) { blendIndicesList.Add(x); blendIndicesList.Add(y); blendIndicesList.Add(z); blendIndicesList2.Add(new int[] { x, y, z }); } else if (weightCounts[j] == 4) { blendIndicesList.Add(x); blendIndicesList.Add(y); blendIndicesList.Add(z); blendIndicesList.Add(w); blendIndicesList2.Add(new int[] { x, y, z, w }); } } } /* * ----------------- * Texture Coordinates * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[coordinates].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[coordinates].VertexDataBlock] + meshDataInfoList[coordinates].Offset, SeekOrigin.Begin); float x = 0; float y = 0; float z = 0; float w = 0; if (meshDataInfoList[coordinates].DataType == 13 || meshDataInfoList[coordinates].DataType == 14) { var sx = (ushort)br1.ReadInt16(); var sy = (ushort)br1.ReadInt16(); var sz = (ushort)br1.ReadInt16(); var sw = (ushort)br1.ReadInt16(); var h1 = new SharpDX.Half(sx); var h2 = new SharpDX.Half(sy); var h3 = new SharpDX.Half(sz); var h4 = new SharpDX.Half(sw); x = h1; y = h2; z = h3; w = h4; } else if (meshDataInfoList[coordinates].DataType == 1) { x = br1.ReadSingle(); y = br1.ReadSingle(); } else { x = br1.ReadSingle(); y = br1.ReadSingle(); z = br1.ReadSingle(); w = br1.ReadSingle(); } var ox = x - Math.Truncate(x); var oy = y - Math.Truncate(y); objBytes.Add("vt " + ox.ToString("N5") + " " + (1 - y).ToString("N5") + " "); texCoordList.Add(new Vector2(x, y)); texCoordList2.Add(new Vector2(z, w)); } } /* * ----------------- * Normals * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[normals].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[normals].VertexDataBlock] + meshDataInfoList[normals].Offset, SeekOrigin.Begin); float x = 0; float y = 0; float z = 0; float w = 0; if (meshDataInfoList[normals].DataType == 13 || meshDataInfoList[normals].DataType == 14) { System.Half h1 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h2 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h3 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h4 = System.Half.ToHalf((ushort)br1.ReadInt16()); x = HalfHelper.HalfToSingle(h1); y = HalfHelper.HalfToSingle(h2); z = HalfHelper.HalfToSingle(h3); w = HalfHelper.HalfToSingle(h4); } else { x = br1.ReadSingle(); y = br1.ReadSingle(); z = br1.ReadSingle(); } var nv = new Vector3(x, y, z); objBytes.Add("vn " + x.ToString("N5") + " " + y.ToString("N5") + " " + z.ToString("N5") + " "); normalList.Add(nv); } } /* * ----------------- * Tangents * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[tangents].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[tangents].VertexDataBlock] + meshDataInfoList[tangents].Offset, SeekOrigin.Begin); int x = br1.ReadByte(); int y = br1.ReadByte(); int z = br1.ReadByte(); int w = br1.ReadByte(); var x1 = x * 2 / 255f - 1f; var y1 = y * 2 / 255f - 1f; var z1 = z * 2 / 255f - 1f; var w1 = w * 2 / 255f - 1f; var nv = new Vector3(x1, y1, z1); tangentList.Add(nv); } } /* * ----------------- * Vertex Color * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[colors].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[colors].VertexDataBlock] + meshDataInfoList[colors].Offset, SeekOrigin.Begin); int a = br1.ReadByte(); int r = br1.ReadByte(); int g = br1.ReadByte(); int b = br1.ReadByte(); colorsList.Add(new Color4(r, g, b, a)); } } /* * ----------------- * Index * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.IndexData))) { for (int j = 0; j < mesh.MeshInfo.IndexCount; j += 3) { int i1 = br1.ReadInt16(); int i2 = br1.ReadInt16(); int i3 = br1.ReadInt16(); objBytes.Add("f " + (i1 + 1) + "/" + (i1 + 1) + "/" + (i1 + 1) + " " + (i2 + 1) + "/" + (i2 + 1) + "/" + (i2 + 1) + " " + (i3 + 1) + "/" + (i3 + 1) + "/" + (i3 + 1) + " "); indexList.Add(i1); indexList.Add(i2); indexList.Add(i3); } } ModelMeshData modelMeshData = new ModelMeshData() { Vertices = vertexList, Normals = normalList, TextureCoordinates = texCoordList, TextureCoordinates2 = texCoordList2, BiTangents = tangentList, Indices = indexList, VertexColors = colorsList, OBJFileData = objBytes.ToArray(), BoneStrings = boneStrings, BoneIndices = modelData.BoneIndicies, BoneTransforms = boneTransforms, BlendWeights = blendWeightList, BlendIndices = blendIndicesList, WeightCounts = weightCounts, MeshPartList = mesh.MeshPartList, BlendIndicesArrayList = blendIndicesList2, BlendWeightsArrayList = blendWeightList2, MaterialNum = mesh.MeshInfo.MaterialNum, MeshPartCount = mesh.MeshInfo.MeshPartCount, MeshPartOffset = mesh.MeshInfo.MeshPartOffset }; meshList.Add(modelMeshData); } } }
/// <summary> /// Reads the model data for specified item and converts it into a .obj file /// </summary> /// <param name="itemID">The item ID</param> /// <param name="raceID">The currently selected races ID</param> /// <param name="part">items equipment slot</param> /// <param name="parentNode">Equipment slot name</param> /// <param name="childNode">Item Name</param> public Read3D(string itemID, string raceID, string part, string parentNode, string childNode) { string modelFolder, modelFile; modelFolder = "chara/equipment/e" + itemID + "/model"; modelFile = "c" + raceID + "e" + itemID + "_" + part + ".mdl"; FindOffset fo = new FindOffset(modelFile); string offset = fo.getFileOffset(); int loc = ((int.Parse(offset, NumberStyles.HexNumber) / 8) & 0x000f) / 2; using (BinaryReader br = new BinaryReader(File.OpenRead(Properties.Settings.Default.DefaultDir + "/040000.win32.dat" + loc))) { int initialOffset = int.Parse(offset, NumberStyles.HexNumber); if (loc == 1) { initialOffset = initialOffset - 16; } else if (loc == 2) { initialOffset = initialOffset - 32; } else if (loc == 3) { initialOffset = initialOffset - 48; } List <byte> byteList = new List <byte>(); br.BaseStream.Seek(initialOffset, SeekOrigin.Begin); int headerLength = br.ReadInt32(); int type = br.ReadInt32(); int decompressedSize = br.ReadInt32(); br.ReadBytes(8); int parts = br.ReadInt16(); int endOfHeader = initialOffset + headerLength; int partCount = 0; byteList.AddRange(new byte[68]); br.BaseStream.Seek(initialOffset + 24, SeekOrigin.Begin); int[] chunkUncompSizes = new int[11]; int[] chunkLengths = new int[11]; int[] chunkOffsets = new int[11]; int[] chunkBlockStart = new int[11]; int[] chunkNumBlocks = new int[11]; for (int f = 0; f < 11; f++) { chunkUncompSizes[f] = br.ReadInt32(); } for (int f = 0; f < 11; f++) { chunkLengths[f] = br.ReadInt32(); } for (int f = 0; f < 11; f++) { chunkOffsets[f] = br.ReadInt32(); } for (int f = 0; f < 11; f++) { chunkBlockStart[f] = br.ReadInt16(); } int totalBlocks = 0; for (int f = 0; f < 11; f++) { chunkNumBlocks[f] = br.ReadInt16(); totalBlocks += chunkNumBlocks[f]; } meshCount = br.ReadInt16(); materialCount = br.ReadInt16(); br.ReadBytes(4); int[] blockSizes = new int[totalBlocks]; for (int f = 0; f < totalBlocks; f++) { blockSizes[f] = br.ReadInt16(); } br.BaseStream.Seek(initialOffset + headerLength + chunkOffsets[0], SeekOrigin.Begin); for (int i = 0; i < blockSizes.Length; i++) { int lastPos = (int)br.BaseStream.Position; br.ReadBytes(8); int partCompressedSize = br.ReadInt32(); int partDecompressedSize = br.ReadInt32(); if (partCompressedSize == 32000) { byte[] forlist = br.ReadBytes(partDecompressedSize); byteList.AddRange(forlist); } else { byte[] forlist = br.ReadBytes(partCompressedSize); byte[] partDecompressedBytes = new byte[partDecompressedSize]; using (MemoryStream ms = new MemoryStream(forlist)) { using (DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress)) { int count = ds.Read(partDecompressedBytes, 0x00, partDecompressedSize); } } byteList.AddRange(partDecompressedBytes); } br.BaseStream.Seek(lastPos + blockSizes[i], SeekOrigin.Begin); } decompBytes = byteList.ToArray(); } using (BinaryReader br = new BinaryReader(new MemoryStream(decompBytes))) { Model model = new Model(meshCount, materialCount); for (int x = 0; x < 3; x++) { List <MeshInfo> mInfo = new List <MeshInfo>(); for (int i = 0; i < meshCount / 3; i++) { mInfo.Clear(); br.BaseStream.Seek((x * 136) + 68, SeekOrigin.Begin); int dataArrayNum = br.ReadByte(); while (dataArrayNum != 255) { MeshInfo meshInfo = new MeshInfo(dataArrayNum, br.ReadByte(), br.ReadByte(), br.ReadByte()); mInfo.Add(meshInfo); br.ReadBytes(4); dataArrayNum = br.ReadByte(); } model.Quality[x].meshInfoDict.Add(i, mInfo.ToArray()); } } br.BaseStream.Seek(136 * meshCount + 68, SeekOrigin.Begin); model.numStrings = br.ReadInt32(); model.stringBlockSize = br.ReadInt32(); br.ReadBytes(model.stringBlockSize); br.ReadBytes(4); model.numTotalMeshes = br.ReadInt16(); model.numAtrStrings = br.ReadInt16(); model.numParts = br.ReadInt16(); model.numMaterialStrings = br.ReadInt16(); model.numBoneStrings = br.ReadInt16(); model.numBoneLists = br.ReadInt16(); model.unk1 = br.ReadInt16(); model.unk2 = br.ReadInt16(); model.unk3 = br.ReadInt16(); model.unk4 = br.ReadInt16(); model.unk5 = br.ReadInt16(); model.unk6 = br.ReadInt16(); br.ReadBytes(10); model.unk7 = br.ReadInt16(); br.ReadBytes(16); br.ReadBytes(32 * model.unk5); for (int i = 0; i < 3; i++) { model.Quality[i].meshOffset = br.ReadInt16(); model.Quality[i].numMeshes = br.ReadInt16(); br.ReadBytes(40); model.Quality[i].vertDataSize = br.ReadInt32(); model.Quality[i].indexDataSize = br.ReadInt32(); model.Quality[i].vertOffset = br.ReadInt32(); model.Quality[i].indexOffset = br.ReadInt32(); } for (int x = 0; x < 3; x++) { for (int i = 0; i < meshCount / 3; i++) { Mesh m = new Mesh(); m.numVerts = br.ReadInt32(); m.numIndex = br.ReadInt32(); m.materialNumber = br.ReadInt16(); m.partTableOffset = br.ReadInt16(); m.partTableCount = br.ReadInt16(); m.boneListIndex = br.ReadInt16(); m.indexDataOffset = br.ReadInt32(); for (int j = 0; j < 3; j++) { m.vertexDataOffsets[j] = br.ReadInt32(); } for (int k = 0; k < 3; k++) { m.vertexSizes[k] = br.ReadByte(); } m.numBuffers = br.ReadByte(); model.Quality[x].mesh[i] = m; } } br.ReadBytes(model.numAtrStrings * 4); br.ReadBytes(model.unk6 * 20); model.setMeshParts(); for (int i = 0; i < model.numParts; i++) { MeshPart mp = new MeshPart(); mp.indexOffset = br.ReadInt32(); mp.indexCount = br.ReadInt32(); mp.attributes = br.ReadInt32(); mp.boneReferenceOffset = br.ReadInt16(); mp.boneReferenceCount = br.ReadInt16(); model.meshPart[i] = mp; } //something with attribute masks br.ReadBytes(model.unk7 * 12); br.ReadBytes(model.numMaterialStrings * 4); br.ReadBytes(model.numBoneStrings * 4); model.setBoneList(); for (int i = 0; i < model.numBoneLists; i++) { BoneList bl = new BoneList(); for (int j = 0; j < 64; j++) { bl.boneList[j] = br.ReadInt16(); } bl.boneCount = br.ReadInt32(); model.boneList[i] = bl; } br.ReadBytes(model.unk1 * 16); br.ReadBytes(model.unk2 * 12); br.ReadBytes(model.unk3 * 4); model.boneIndexSize = br.ReadInt32(); model.setBoneIndicies(); for (int i = 0; i < model.boneIndexSize / 2; i++) { model.boneIndicies[i] = br.ReadInt16(); } int padding = br.ReadByte(); br.ReadBytes(padding); for (int i = 0; i < model.bb.Length; i++) { BoundingBoxes bb = new BoundingBoxes(); for (int j = 0; j < 4; j++) { bb.pointA[j] = br.ReadSingle(); } for (int k = 0; k < 4; k++) { bb.pointB[k] = br.ReadSingle(); } model.bb[i] = bb; } for (int i = 0; i < 3; i++) { for (int j = 0; j < model.Quality[i].numMeshes; j++) { Mesh m = model.Quality[i].mesh[j]; m.setMeshData(); for (int k = 0; k < m.numBuffers; k++) { br.BaseStream.Seek(model.Quality[i].vertOffset + m.vertexDataOffsets[k], SeekOrigin.Begin); MeshData md = new MeshData(); md.meshData = br.ReadBytes(m.vertexSizes[k] * m.numVerts); m.meshData[k] = md; } br.BaseStream.Seek(model.Quality[i].indexOffset + (m.indexDataOffset * 2), SeekOrigin.Begin); m.indexData = br.ReadBytes(2 * m.numIndex); } } List <string> objBytes = new List <string>(); int vertexs = 0, coordinates = 0, normals = 0; for (int i = 0; i < model.Quality[0].numMeshes; i++) { objBytes.Clear(); Mesh m = model.Quality[0].mesh[i]; MeshInfo[] mi = model.Quality[0].meshInfoDict[i]; int c = 0; foreach (var a in mi) { if (a.useType == 0) { vertexs = c; } else if (a.useType == 3) { normals = c; } else if (a.useType == 4) { coordinates = c; } c++; } using (BinaryReader br1 = new BinaryReader(new MemoryStream(m.meshData[mi[vertexs].dataArrayNum].meshData))) { for (int j = 0; j < m.numVerts; j++) { int offset1 = j * m.vertexSizes[mi[vertexs].dataArrayNum] + mi[vertexs].offset; br1.BaseStream.Seek(offset1, SeekOrigin.Begin); if (mi[vertexs].dataType == 13 || mi[vertexs].dataType == 14) { float f1, f2, f3; Half h1 = Half.ToHalf((ushort)br1.ReadInt16()); Half h2 = Half.ToHalf((ushort)br1.ReadInt16()); Half h3 = Half.ToHalf((ushort)br1.ReadInt16()); f1 = HalfHelper.HalfToSingle(h1); f2 = HalfHelper.HalfToSingle(h2); f3 = HalfHelper.HalfToSingle(h3); objBytes.Add("v " + f1.ToString() + " " + f2.ToString() + " " + f3.ToString() + " "); } else if (mi[vertexs].dataType == 2) { float f1, f2, f3; f1 = br1.ReadSingle(); f2 = br1.ReadSingle(); f3 = br1.ReadSingle(); objBytes.Add("v " + f1.ToString() + " " + f2.ToString() + " " + f3.ToString() + " "); } } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(m.meshData[mi[coordinates].dataArrayNum].meshData))) { for (int j = 0; j < m.numVerts; j++) { int offset1 = j * m.vertexSizes[mi[coordinates].dataArrayNum] + mi[coordinates].offset; br1.BaseStream.Seek(offset1, SeekOrigin.Begin); Half a1 = Half.ToHalf((ushort)br1.ReadInt16()); Half b1 = Half.ToHalf((ushort)br1.ReadInt16()); float a = HalfHelper.HalfToSingle(a1); float b = (HalfHelper.HalfToSingle(b1)); objBytes.Add("vt " + a.ToString() + " " + b.ToString() + " "); } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(m.meshData[mi[normals].dataArrayNum].meshData))) { for (int j = 0; j < m.numVerts; j++) { br1.BaseStream.Seek(j * m.vertexSizes[mi[normals].dataArrayNum] + mi[normals].offset, SeekOrigin.Begin); Half h1 = Half.ToHalf((ushort)br1.ReadInt16()); Half h2 = Half.ToHalf((ushort)br1.ReadInt16()); Half h3 = Half.ToHalf((ushort)br1.ReadInt16()); objBytes.Add("vn " + HalfHelper.HalfToSingle(h1).ToString() + " " + HalfHelper.HalfToSingle(h2).ToString() + " " + HalfHelper.HalfToSingle(h3).ToString() + " "); } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(m.indexData))) { for (int j = 0; j < m.numIndex; j += 3) { int a1 = br1.ReadInt16() + 1; int b1 = br1.ReadInt16() + 1; int c1 = br1.ReadInt16() + 1; objBytes.Add("f " + a1 + "/" + a1 + "/" + a1 + " " + b1 + "/" + b1 + "/" + b1 + " " + c1 + "/" + c1 + "/" + c1 + " "); } } Directory.CreateDirectory(Properties.Settings.Default.SaveDir + "/" + parentNode + "/" + childNode); File.WriteAllLines(Properties.Settings.Default.SaveDir + "/" + parentNode + "/" + childNode + "/Mesh_" + i + ".obj", objBytes.ToArray()); } } }
/// <summary> /// Parses the MDL file to obtain model information /// </summary> /// <param name="selectedItem">The currently selected item</param> /// <param name="selectedRace">The currently selected race</param> /// <param name="selectedBody">The currently selected body</param> /// <param name="selectedPart">The currently selected part</param> /// <param name="selectedCategory">The items category </param> public MDL(ItemData selectedItem, string selectedCategory, string selectedRace, string selectedBody, string selectedPart) { string itemType = Helper.GetCategoryType(selectedCategory); string MDLFolder = ""; if (itemType.Equals("weapon") || itemType.Equals("food")) { if (selectedPart.Equals("Secondary")) { MDLFolder = string.Format(Strings.WeapMDLFolder, selectedItem.SecondaryModelID, selectedItem.SecondaryModelBody); MDLFile = string.Format(Strings.WeapMDLFile, selectedItem.SecondaryModelID, selectedItem.SecondaryModelBody); } else { MDLFolder = string.Format(Strings.WeapMDLFolder, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); MDLFile = string.Format(Strings.WeapMDLFile, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); } } else if (itemType.Equals("accessory")) { MDLFolder = string.Format(Strings.AccMDLFolder, selectedItem.PrimaryModelID); MDLFile = string.Format(Strings.AccMDLFile, selectedRace, selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } else if (itemType.Equals("character")) { if (selectedItem.ItemName.Equals(Strings.Body)) { MDLFolder = string.Format(Strings.BodyMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.BodyMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Face)) { MDLFolder = string.Format(Strings.FaceMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.FaceMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Hair)) { MDLFolder = string.Format(Strings.HairMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.HairMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Tail)) { MDLFolder = string.Format(Strings.TailMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.TailMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } } else if (itemType.Equals("monster")) { bool isDemiHuman = false; if (selectedItem.PrimaryMTRLFolder != null) { isDemiHuman = selectedItem.PrimaryMTRLFolder.Contains("demihuman"); } if (isDemiHuman) { MDLFolder = string.Format(Strings.DemiMDLFolder, selectedItem.PrimaryModelID.PadLeft(4, '0'), selectedItem.PrimaryModelBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.DemiMDLFile, selectedItem.PrimaryModelID.PadLeft(4, '0'), selectedItem.PrimaryModelBody, selectedPart); } else { MDLFolder = string.Format(Strings.MonsterMDLFolder, selectedItem.PrimaryModelID.PadLeft(4, '0'), selectedItem.PrimaryModelBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.MonsterMDLFile, selectedItem.PrimaryModelID.PadLeft(4, '0'), selectedItem.PrimaryModelBody.PadLeft(4, '0')); } } else { MDLFolder = string.Format(Strings.EquipMDLFolder, selectedItem.PrimaryModelID); if (selectedPart.Equals("-")) { MDLFile = string.Format(Strings.EquipMDLFile, selectedRace, selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } else { MDLFile = string.Format(Strings.EquipMDLFile, selectedRace, selectedItem.PrimaryModelID, selectedPart); } } fullPath = MDLFolder + "/" + MDLFile; int offset = Helper.GetDataOffset(FFCRC.GetHash(MDLFolder), FFCRC.GetHash(MDLFile), Strings.ItemsDat); if (offset == 0) { if (itemType.Equals("weapon")) { if (selectedPart.Equals("Secondary")) { MDLFolder = string.Format(Strings.EquipMDLFolder, selectedItem.SecondaryModelID); MDLFile = string.Format(Strings.EquipMDLFile, "0101", selectedItem.SecondaryModelID, Info.slotAbr[Strings.Hands]); offset = Helper.GetDataOffset(FFCRC.GetHash(MDLFolder), FFCRC.GetHash(MDLFile), Strings.ItemsDat); } } } int datNum = ((offset / 8) & 0x000f) / 2; var MDLDatData = Helper.GetType3DecompressedData(offset, datNum, Strings.ItemsDat); using (BinaryReader br = new BinaryReader(new MemoryStream(MDLDatData.Item1))) { // The size of the header + (size of the mesh information block (136 bytes) * the meshes) + padding br.BaseStream.Seek(64 + 136 * MDLDatData.Item2 + 4, SeekOrigin.Begin); var modelStringCount = br.ReadInt32(); var stringBlockSize = br.ReadInt32(); var stringBlock = br.ReadBytes(stringBlockSize); var unknown = br.ReadBytes(4); var totalMeshCount = br.ReadInt16(); var attributeStringCount = br.ReadInt16(); var meshPartsCount = br.ReadInt16(); var materialStringCount = br.ReadInt16(); var boneStringCount = br.ReadInt16(); var boneListCount = br.ReadInt16(); //Has something to do with amount of extra vertex data. var unknown1 = br.ReadInt16(); //Has something to do with amount of extra vertex data. var unknown2 = br.ReadInt16(); var unknown3 = br.ReadInt16(); // Seems to always be 1027 var unknown4 = br.ReadInt16(); var unknown5 = br.ReadInt16(); var unknown6 = br.ReadInt16(); br.ReadBytes(10); var unknown7 = br.ReadInt16(); br.ReadBytes(16); using (BinaryReader br1 = new BinaryReader(new MemoryStream(stringBlock))) { br1.BaseStream.Seek(0, SeekOrigin.Begin); for (int i = 0; i < attributeStringCount; i++) { byte a; List <byte> atrName = new List <byte>(); while ((a = br1.ReadByte()) != 0) { atrName.Add(a); } string atr = Encoding.ASCII.GetString(atrName.ToArray()); atr = atr.Replace("\0", ""); modelData.Attributes.Add(atr); atrStrings.Add(atr); } for (int i = 0; i < boneStringCount; i++) { byte b; List <byte> boneName = new List <byte>(); while ((b = br1.ReadByte()) != 0) { boneName.Add(b); } string bone = Encoding.ASCII.GetString(boneName.ToArray()); bone = bone.Replace("\0", ""); modelData.Bones.Add(bone); boneStrings.Add(bone); } for (int i = 0; i < materialStringCount; i++) { byte b; List <byte> name = new List <byte>(); while ((b = br1.ReadByte()) != 0) { name.Add(b); } string material = Encoding.ASCII.GetString(name.ToArray()); material = material.Replace("\0", ""); modelData.Materials.Add(material); materialStrings.Add(material); } } byte[] unknown5Bytes = br.ReadBytes(32 * unknown5); for (int i = 0; i < 3; i++) { LevelOfDetail LoD = new LevelOfDetail(); LoD.MeshOffset = br.ReadInt16(); LoD.MeshCount = br.ReadInt16(); br.ReadBytes(40); LoD.VertexDataSize = br.ReadInt32(); LoD.IndexDataSize = br.ReadInt32(); LoD.VertexOffset = br.ReadInt32(); LoD.IndexOffset = br.ReadInt32(); modelData.LoD.Add(LoD); } var savePos = br.BaseStream.Position; var lodStructPos = 68; for (int i = 0; i < modelData.LoD.Count; i++) { List <MeshDataInfo> meshInfoList = new List <MeshDataInfo>(); for (int j = 0; j < modelData.LoD[i].MeshCount; j++) { modelData.LoD[i].MeshList.Add(new Mesh()); meshInfoList.Clear(); br.BaseStream.Seek((j * 136) + lodStructPos, SeekOrigin.Begin); var dataBlockNum = br.ReadByte(); while (dataBlockNum != 255) { MeshDataInfo meshInfo = new MeshDataInfo() { VertexDataBlock = dataBlockNum, Offset = br.ReadByte(), DataType = br.ReadByte(), UseType = br.ReadByte() }; meshInfoList.Add(meshInfo); br.ReadBytes(4); dataBlockNum = br.ReadByte(); } modelData.LoD[i].MeshList[j].MeshDataInfoList = meshInfoList.ToArray(); } lodStructPos += 136 * modelData.LoD[i].MeshCount; } br.BaseStream.Seek(savePos, SeekOrigin.Begin); for (int x = 0; x < modelData.LoD.Count; x++) { for (int i = 0; i < modelData.LoD[x].MeshCount; i++) { MeshInfo meshInfo = new MeshInfo() { VertexCount = br.ReadInt32(), IndexCount = br.ReadInt32(), MaterialNum = br.ReadInt16(), MeshPartOffset = br.ReadInt16(), MeshPartCount = br.ReadInt16(), BoneListIndex = br.ReadInt16(), IndexDataOffset = br.ReadInt32() }; modelData.LoD[x].MeshList[i].MaterialId = meshInfo.MaterialNum; var typeChar = materialStrings[meshInfo.MaterialNum][4].ToString() + materialStrings[meshInfo.MaterialNum][9].ToString(); modelData.LoD[x].MeshList[i].BoneListIndex = meshInfo.BoneListIndex; if (typeChar.Equals("cb")) { modelData.LoD[x].MeshList[i].IsBody = true; } for (int j = 0; j < 3; j++) { meshInfo.VertexDataOffsets.Add(br.ReadInt32()); } for (int k = 0; k < 3; k++) { meshInfo.VertexSizes.Add(br.ReadByte()); } meshInfo.VertexDataBlockCount = br.ReadByte(); modelData.LoD[x].MeshList[i].MeshInfo = meshInfo; } } byte[] attributeOffsetBytes = br.ReadBytes(attributeStringCount * 4); br.ReadBytes(unknown6 * 20); for (int i = 0; i < modelData.LoD.Count; i++) { foreach (var mesh in modelData.LoD[i].MeshList) { for (int j = 0; j < mesh.MeshInfo.MeshPartCount; j++) { MeshPart meshPart = new MeshPart() { IndexOffset = br.ReadInt32(), IndexCount = br.ReadInt32(), Attributes = br.ReadInt32(), BoneOffset = br.ReadInt16(), BoneCount = br.ReadInt16() }; mesh.MeshPartList.Add(meshPart); } } } br.ReadBytes(unknown7 * 12); br.ReadBytes(materialStringCount * 4); List <int> boneIncrements = new List <int>(); // Loop through the increments and save their data. for (int i = 0; i < boneStringCount; i++) { int increment = br.ReadInt32(); boneIncrements.Add(increment); } for (int i = 0; i < boneListCount; i++) { Bones bones = new Bones(); for (int j = 0; j < 64; j++) { bones.BoneData.Add(br.ReadInt16()); } bones.BoneCount = br.ReadInt32(); modelData.BoneSet.Add(bones); } //br.ReadBytes(unknown1 * 16); Dictionary <int, int> indexMin = new Dictionary <int, int>(); Dictionary <int, List <int> > extraIndices = new Dictionary <int, List <int> >(); Dictionary <int, List <int> > extraIndices2 = new Dictionary <int, List <int> >(); var indexCounts = new List <List <ExtraIndex> >(); // One for each LoD level. indexCounts.Add(new List <ExtraIndex>()); indexCounts.Add(new List <ExtraIndex>()); indexCounts.Add(new List <ExtraIndex>()); var pCounts = new int[3]; if (unknown1 > 0) { for (int i = 0; i < unknown1; i++) { //not sure br.ReadBytes(4); //LoD[0] Extra Data Index var p1 = br.ReadUInt16(); //LoD[1] Extra Data Index var p2 = br.ReadUInt16(); //LoD[2] Extra Data Index var p3 = br.ReadUInt16(); //LoD[0] Extra Data Part Count var p1n = br.ReadUInt16(); pCounts[0] += p1n; //LoD[1] Extra Data Part Count var p2n = br.ReadUInt16(); pCounts[1] += p2n; //LoD[2] Extra Data Part Count var p3n = br.ReadUInt16(); pCounts[2] += p3n; } } Dictionary <int, int> indexLoc = new Dictionary <int, int>(); if (unknown1 > 0) { for (int i = 0; i < modelData.LoD[LoDViewLevel].MeshCount; i++) { var ido = modelData.LoD[LoDViewLevel].MeshList[i].MeshInfo.IndexDataOffset; if (!indexLoc.ContainsKey(ido)) { indexLoc.Add(ido, i); } } } var totalMaskCounts = new int[3]; Dictionary <int, int> totalExtraCounts = new Dictionary <int, int>(); if (unknown2 > 0) { for (int x = 0; x < pCounts.Length; x++) { for (int i = 0; i < pCounts[x]; i++) { //Index Offset Start var m1 = br.ReadInt32(); //index count var mCount = br.ReadInt32(); //index offset in unk3 var mOffset = br.ReadInt32(); var iLoc = 0; if (indexLoc.ContainsKey(m1)) { iLoc = indexLoc[m1]; } indexCounts[x].Add(new ExtraIndex() { IndexLocation = iLoc, IndexCount = mCount }); totalMaskCounts[x] += mCount; } } } if (unknown3 > 0) { //var unk3Remainder = (unknown3 * 4) - (totalLoD0MaskCount * 4); var c = 0; for (int l = 0; l < indexCounts.Count; l++) { foreach (var ic in indexCounts[l]) { HashSet <int> mIndexList = new HashSet <int>(); for (int i = 0; i < ic.IndexCount; i++) { //index its replacing? attatched to? var oIndex = br.ReadUInt16(); //extra index following last equipment index var mIndex = br.ReadUInt16(); if (l == LoDViewLevel) { mIndexList.Add(mIndex); if (extraIndices.ContainsKey(ic.IndexLocation)) { extraIndices[ic.IndexLocation].Add(mIndex); extraIndices2[ic.IndexLocation].Add(oIndex); } else { extraIndices.Add(ic.IndexLocation, new List <int>() { mIndex }); extraIndices2.Add(ic.IndexLocation, new List <int>() { oIndex }); } } } if (l == LoDViewLevel) { if (totalExtraCounts.ContainsKey(ic.IndexLocation)) { totalExtraCounts[ic.IndexLocation] += mIndexList.Count; } else { totalExtraCounts.Add(ic.IndexLocation, mIndexList.Count); } } c++; } } //the rest of unk3 //br.ReadBytes(unk3Remainder); foreach (var ei in extraIndices) { indexMin.Add(ei.Key, ei.Value.Min()); } extraIndexData.indexCounts = indexCounts[LoDViewLevel]; extraIndexData.indexMin = indexMin; extraIndexData.totalExtraCounts = totalExtraCounts; extraIndexData.extraIndices = extraIndices; extraIndexData.extraIndices2 = extraIndices2; modelData.ExtraData = extraIndexData; } //br.ReadBytes(unknown3 * 4); var boneIndexSize = br.ReadInt32(); for (int i = 0; i < boneIndexSize / 2; i++) { modelData.BoneIndicies.Add(br.ReadUInt16()); } int padding = br.ReadByte(); br.ReadBytes(padding); for (int i = 0; i < 4; i++) { ModelMaterial.BoundingBox boundingBox = new ModelMaterial.BoundingBox(); for (int j = 0; j < 4; j++) { boundingBox.PointA.Add(br.ReadSingle()); } for (int k = 0; k < 4; k++) { boundingBox.PointB.Add(br.ReadSingle()); } modelData.BoundingBoxes.Add(boundingBox); } //float4x4 for (int i = 0; i < boneStringCount; i++) { string boneName = boneStrings[i]; Vector4 transform1 = new Vector4(); Vector4 transform2 = new Vector4(); transform1.X = br.ReadSingle(); transform1.Y = br.ReadSingle(); transform1.Z = br.ReadSingle(); transform1.W = br.ReadSingle(); transform2.X = br.ReadSingle(); transform2.Y = br.ReadSingle(); transform2.Z = br.ReadSingle(); transform2.W = br.ReadSingle(); boneTransforms.Add(transform1.X); boneTransforms.Add(transform1.Y); boneTransforms.Add(transform1.Z); boneTransforms.Add(transform1.W); boneTransforms.Add(transform2.X); boneTransforms.Add(transform2.Y); boneTransforms.Add(transform2.Z); boneTransforms.Add(transform2.W); } for (int i = 0; i < 3; i++) { for (int j = 0; j < modelData.LoD[i].MeshCount; j++) { Mesh mesh = modelData.LoD[i].MeshList[j]; for (int k = 0; k < mesh.MeshInfo.VertexDataBlockCount; k++) { br.BaseStream.Seek(modelData.LoD[i].VertexOffset + mesh.MeshInfo.VertexDataOffsets[k], SeekOrigin.Begin); mesh.MeshVertexData.Add(br.ReadBytes(mesh.MeshInfo.VertexSizes[k] * mesh.MeshInfo.VertexCount)); } br.BaseStream.Seek(modelData.LoD[i].IndexOffset + (mesh.MeshInfo.IndexDataOffset * 2), SeekOrigin.Begin); mesh.IndexData = br.ReadBytes(2 * mesh.MeshInfo.IndexCount); } } int vertex = 0, coordinates = 0, normals = 0, tangents = 0, colors = 0, blendWeights = 0, blendIndices = 0; for (int i = 0; i < modelData.LoD[LoDViewLevel].MeshCount; i++) { objBytes.Clear(); var vertexList = new Vector3Collection(); var texCoordList = new Vector2Collection(); var texCoordList2 = new Vector2Collection(); var normalList = new Vector3Collection(); var tangentList = new Vector3Collection(); var colorsList = new Color4Collection(); var indexList = new IntCollection(); var blendWeightList = new List <float>(); var blendWeightList2 = new List <float[]>(); var blendIndicesList = new List <int>(); var blendIndicesList2 = new List <int[]>(); var weightCounts = new List <int>(); var extraVerts = new HashSet <Vector3>(); Dictionary <int, Vector3> extraVertDict = new Dictionary <int, Vector3>(); Mesh mesh = modelData.LoD[LoDViewLevel].MeshList[i]; MeshDataInfo[] meshDataInfoList = mesh.MeshDataInfoList; int c = 0; foreach (var meshDataInfo in meshDataInfoList) { if (meshDataInfo.UseType == 0) { vertex = c; } else if (meshDataInfo.UseType == 1) { blendWeights = c; } else if (meshDataInfo.UseType == 2) { blendIndices = c; } else if (meshDataInfo.UseType == 3) { normals = c; } else if (meshDataInfo.UseType == 4) { coordinates = c; } else if (meshDataInfo.UseType == 6) { tangents = c; } else if (meshDataInfo.UseType == 7) { colors = c; } c++; } /* * ----------------- * Vertex * ----------------- */ // Only actually read the buffers if they have data in them. if (mesh.MeshVertexData.Count > 0) { using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[vertex].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[vertex].VertexDataBlock] + meshDataInfoList[vertex].Offset, SeekOrigin.Begin); Vector3 vVector = new Vector3(); if (meshDataInfoList[vertex].DataType == 13 || meshDataInfoList[vertex].DataType == 14) { System.Half h1 = System.Half.ToHalf(br1.ReadUInt16()); System.Half h2 = System.Half.ToHalf(br1.ReadUInt16()); System.Half h3 = System.Half.ToHalf(br1.ReadUInt16()); float x = HalfHelper.HalfToSingle(h1); float y = HalfHelper.HalfToSingle(h2); float z = HalfHelper.HalfToSingle(h3); vVector = new Vector3(x, y, z); objBytes.Add("v " + x.ToString("N5") + " " + y.ToString("N5") + " " + z.ToString("N5") + " "); } else if (meshDataInfoList[vertex].DataType == 2) { var x = BitConverter.ToSingle(br1.ReadBytes(4), 0); var y = BitConverter.ToSingle(br1.ReadBytes(4), 0); var z = BitConverter.ToSingle(br1.ReadBytes(4), 0); vVector = new Vector3(x, y, z); objBytes.Add("v " + x.ToString("N5") + " " + y.ToString("N5") + " " + z.ToString("N5") + " "); } vertexList.Add(vVector); } } /* * ----------------- * Blend Weight * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[blendWeights].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[blendWeights].VertexDataBlock] + meshDataInfoList[blendWeights].Offset, SeekOrigin.Begin); float x = br1.ReadByte() / 255.0f; float y = br1.ReadByte() / 255.0f; float z = br1.ReadByte() / 255.0f; float w = br1.ReadByte() / 255.0f; int count = 0; if (x != 0) { blendWeightList.Add(x); count++; if (y != 0) { blendWeightList.Add(y); count++; if (z != 0) { blendWeightList.Add(z); count++; if (w != 0) { blendWeightList.Add(w); count++; } } } } if (count == 1) { blendWeightList2.Add(new float[] { x }); } else if (count == 2) { blendWeightList2.Add(new float[] { x, y }); } else if (count == 3) { blendWeightList2.Add(new float[] { x, y, z }); } else if (count == 4) { blendWeightList2.Add(new float[] { x, y, z, w }); } weightCounts.Add(count); } } /* * ----------------- * Blend Index * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[blendIndices].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[blendIndices].VertexDataBlock] + meshDataInfoList[blendIndices].Offset, SeekOrigin.Begin); int x = br1.ReadByte(); int y = br1.ReadByte(); int z = br1.ReadByte(); int w = br1.ReadByte(); if (weightCounts[j] == 1) { blendIndicesList.Add(x); blendIndicesList2.Add(new int[] { x }); } else if (weightCounts[j] == 2) { blendIndicesList.Add(x); blendIndicesList.Add(y); blendIndicesList2.Add(new int[] { x, y }); } else if (weightCounts[j] == 3) { blendIndicesList.Add(x); blendIndicesList.Add(y); blendIndicesList.Add(z); blendIndicesList2.Add(new int[] { x, y, z }); } else if (weightCounts[j] == 4) { blendIndicesList.Add(x); blendIndicesList.Add(y); blendIndicesList.Add(z); blendIndicesList.Add(w); blendIndicesList2.Add(new int[] { x, y, z, w }); } } } /* * ----------------- * Texture Coordinates * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[coordinates].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[coordinates].VertexDataBlock] + meshDataInfoList[coordinates].Offset, SeekOrigin.Begin); float x = 0; float y = 0; float z = 0; float w = 0; if (meshDataInfoList[coordinates].DataType == 13 || meshDataInfoList[coordinates].DataType == 14) { var sx = br1.ReadUInt16(); var sy = br1.ReadUInt16(); var sz = br1.ReadUInt16(); var sw = br1.ReadUInt16(); var h1 = new SharpDX.Half(sx); var h2 = new SharpDX.Half(sy); var h3 = new SharpDX.Half(sz); var h4 = new SharpDX.Half(sw); x = h1; y = h2; z = h3; w = h4; } else if (meshDataInfoList[coordinates].DataType == 1) { x = br1.ReadSingle(); y = br1.ReadSingle(); } else { x = br1.ReadSingle(); y = br1.ReadSingle(); z = br1.ReadSingle(); w = br1.ReadSingle(); } var ox = x - Math.Truncate(x); var oy = y - Math.Truncate(y); objBytes.Add("vt " + ox.ToString("N5") + " " + (1 - y).ToString("N5") + " "); texCoordList.Add(new Vector2(x, y)); texCoordList2.Add(new Vector2(z, w)); } } /* * ----------------- * Normals * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[normals].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[normals].VertexDataBlock] + meshDataInfoList[normals].Offset, SeekOrigin.Begin); float x = 0; float y = 0; float z = 0; float w = 0; if (meshDataInfoList[normals].DataType == 13 || meshDataInfoList[normals].DataType == 14) { System.Half h1 = System.Half.ToHalf(br1.ReadUInt16()); System.Half h2 = System.Half.ToHalf(br1.ReadUInt16()); System.Half h3 = System.Half.ToHalf(br1.ReadUInt16()); System.Half h4 = System.Half.ToHalf(br1.ReadUInt16()); x = HalfHelper.HalfToSingle(h1); y = HalfHelper.HalfToSingle(h2); z = HalfHelper.HalfToSingle(h3); w = HalfHelper.HalfToSingle(h4); } else { x = br1.ReadSingle(); y = br1.ReadSingle(); z = br1.ReadSingle(); } var nv = new Vector3(x, y, z); objBytes.Add("vn " + x.ToString("N5") + " " + y.ToString("N5") + " " + z.ToString("N5") + " "); normalList.Add(nv); } } /* * ----------------- * Tangents * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[tangents].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[tangents].VertexDataBlock] + meshDataInfoList[tangents].Offset, SeekOrigin.Begin); int x = br1.ReadByte(); int y = br1.ReadByte(); int z = br1.ReadByte(); int w = br1.ReadByte(); var x1 = x * 2 / 255f - 1f; var y1 = y * 2 / 255f - 1f; var z1 = z * 2 / 255f - 1f; var w1 = w * 2 / 255f - 1f; var nv = new Vector3(x1, y1, z1); tangentList.Add(nv); } } /* * ----------------- * Vertex Color * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[colors].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[colors].VertexDataBlock] + meshDataInfoList[colors].Offset, SeekOrigin.Begin); int a = br1.ReadByte(); int r = br1.ReadByte(); int g = br1.ReadByte(); int b = br1.ReadByte(); colorsList.Add(new Color4(r, g, b, a)); } } } /* * ----------------- * Index * ----------------- */ using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.IndexData))) { for (int j = 0; j < mesh.MeshInfo.IndexCount; j += 3) { int i1 = br1.ReadUInt16(); int i2 = br1.ReadUInt16(); int i3 = br1.ReadUInt16(); objBytes.Add("f " + (i1 + 1) + "/" + (i1 + 1) + "/" + (i1 + 1) + " " + (i2 + 1) + "/" + (i2 + 1) + "/" + (i2 + 1) + " " + (i3 + 1) + "/" + (i3 + 1) + "/" + (i3 + 1) + " "); indexList.Add(i1); indexList.Add(i2); indexList.Add(i3); } } ModelMeshData modelMeshData = new ModelMeshData() { Vertices = vertexList, Normals = normalList, TextureCoordinates = texCoordList, TextureCoordinates2 = texCoordList2, BiTangents = tangentList, Indices = indexList, VertexColors = colorsList, OBJFileData = objBytes.ToArray(), BoneStrings = boneStrings, AttributeStrings = atrStrings, BoneIndices = modelData.BoneIndicies, BoneTransforms = boneTransforms, BlendWeights = blendWeightList, BlendIndices = blendIndicesList, WeightCounts = weightCounts, MeshPartList = mesh.MeshPartList, BlendIndicesArrayList = blendIndicesList2, BlendWeightsArrayList = blendWeightList2, MaterialNum = mesh.MeshInfo.MaterialNum, MeshPartCount = mesh.MeshInfo.MeshPartCount, MeshPartOffset = mesh.MeshInfo.MeshPartOffset }; if (extraIndices2.ContainsKey(i)) { foreach (var id in extraIndices2[i]) { if (!extraVertDict.ContainsKey(id)) { if (modelMeshData.Indices.Count >= id) { var v = 0; try { v = modelMeshData.Indices[id]; } catch { v = 0; } extraVertDict.Add(id, modelMeshData.Vertices[v]); } else { //new Thread(() => MessageBox.Show("There was an error reading the models extra data.\n\n" + // "Mesh " + i + " Index " + id + "\n\n" + // "This is likely caused by parts of a mesh being deleted and may cause crashes in-game.\n\n" + // "Consider using Advanced Import to Fix or Disable Hiding for the above mesh.", // "Extra Data Warning" + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Warning)).Start(); new Thread(() => MessageBox.Show(string.Format(Dialogs.MDLExtraDataWarning, i, id), Dialogs.ExtraDataWarning + Info.appVersion, MessageBoxButtons.OK, MessageBoxIcon.Warning)).Start(); break; } } } } mesh.extraVertDict = extraVertDict; meshList.Add(modelMeshData); } } }
private static float HalfToFloat(BinaryReaderEx src) { ushort val = src.ReadUInt16(Endianness.BigEndian); return(HalfHelper.HalfToSingle(val)); }
/// <summary> /// Write UVVector2 as floats. /// </summary> public void WriteToFile(BinaryWriter writer) { writer.Write(HalfHelper.HalfToSingle(X)); writer.Write(HalfHelper.HalfToSingle(Y)); // writer.Write((Half)1f-Y); }
/// <summary> /// Parses the MDL file to obtain model information /// </summary> /// <param name="selectedItem">The currently selected item</param> /// <param name="selectedRace">The currently selected race</param> /// <param name="selectedBody">The currently selected body</param> /// <param name="selectedPart">The currently selected part</param> /// <param name="selectedCategory">The items category </param> public MDL(ItemData selectedItem, string selectedCategory, string selectedRace, string selectedBody, string selectedPart) { string itemType = Helper.GetCategoryType(selectedCategory); string MDLFolder = ""; if (itemType.Equals("weapon") || itemType.Equals("food")) { if (selectedPart.Equals("Secondary")) { MDLFolder = string.Format(Strings.WeapMDLFolder, selectedItem.SecondaryModelID, selectedItem.SecondaryModelBody); MDLFile = string.Format(Strings.WeapMDLFile, selectedItem.SecondaryModelID, selectedItem.SecondaryModelBody); } else { MDLFolder = string.Format(Strings.WeapMDLFolder, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); MDLFile = string.Format(Strings.WeapMDLFile, selectedItem.PrimaryModelID, selectedItem.PrimaryModelBody); } } else if (itemType.Equals("accessory")) { MDLFolder = string.Format(Strings.AccMDLFolder, selectedItem.PrimaryModelID); MDLFile = string.Format(Strings.AccMDLFile, selectedRace, selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } else if (itemType.Equals("character")) { if (selectedItem.ItemName.Equals(Strings.Body)) { MDLFolder = string.Format(Strings.BodyMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.BodyMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Face)) { MDLFolder = string.Format(Strings.FaceMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.FaceMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Hair)) { MDLFolder = string.Format(Strings.HairMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.HairMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } else if (selectedItem.ItemName.Equals(Strings.Tail)) { MDLFolder = string.Format(Strings.TailMDLFolder, selectedRace, selectedBody.PadLeft(4, '0')); MDLFile = string.Format(Strings.TailMDLFile, selectedRace, selectedBody.PadLeft(4, '0'), selectedPart); } } else if (itemType.Equals("monster")) { bool isDemiHuman = false; if (selectedItem.PrimaryMTRLFolder != null) { isDemiHuman = selectedItem.PrimaryMTRLFolder.Contains("demihuman"); } string ID = ""; string body = ""; if (selectedCategory.Equals(Strings.Pets)) { ID = Info.petID[selectedItem.ItemName]; body = "0001"; } else { ID = selectedItem.PrimaryModelID.PadLeft(4, '0'); body = selectedItem.PrimaryModelBody; } if (isDemiHuman) { MDLFolder = string.Format(Strings.DemiMDLFolder, ID, body); MDLFile = string.Format(Strings.DemiMDLFile, ID, body, selectedPart); } else { MDLFolder = string.Format(Strings.MonsterMDLFolder, ID, body); MDLFile = string.Format(Strings.MonsterMDLFile, ID, body); } } else { MDLFolder = string.Format(Strings.EquipMDLFolder, selectedItem.PrimaryModelID); MDLFile = string.Format(Strings.EquipMDLFile, selectedRace, selectedItem.PrimaryModelID, Info.slotAbr[selectedCategory]); } int offset = Helper.GetItemOffset(FFCRC.GetHash(MDLFolder), FFCRC.GetHash(MDLFile)); int datNum = ((offset / 8) & 0x000f) / 2; offset = Helper.OffsetCorrection(datNum, offset); var MDLDatData = Helper.GetType3DecompressedData(offset, datNum); using (BinaryReader br = new BinaryReader(new MemoryStream(MDLDatData.Item1))) { ModelData modelData = new ModelData(); // The size of the header + (size of the mesh information block (136 bytes) * the number of meshes) + padding br.BaseStream.Seek(64 + 136 * MDLDatData.Item2 + 4, SeekOrigin.Begin); var modelStringCount = br.ReadInt32(); var stringBlockSize = br.ReadInt32(); var stringBlock = br.ReadBytes(stringBlockSize); var unknown = br.ReadBytes(4); var totalMeshCount = br.ReadInt16(); var attributeStringCount = br.ReadInt16(); var meshPartsCount = br.ReadInt16(); var materialStringCount = br.ReadInt16(); var boneStringCount = br.ReadInt16(); var boneListCount = br.ReadInt16(); var unknown1 = br.ReadInt16(); var unknown2 = br.ReadInt16(); var unknown3 = br.ReadInt16(); var unknown4 = br.ReadInt16(); var unknown5 = br.ReadInt16(); var unknown6 = br.ReadInt16(); br.ReadBytes(10); var unknown7 = br.ReadInt16(); br.ReadBytes(16); using (BinaryReader br1 = new BinaryReader(new MemoryStream(stringBlock))) { br1.BaseStream.Seek(0, SeekOrigin.Begin); for (int i = 0; i < attributeStringCount; i++) { while (br1.ReadByte() != 0) { //extract each atribute string here } } for (int i = 0; i < boneStringCount; i++) { while (br1.ReadByte() != 0) { //extact each bone string here } } for (int i = 0; i < materialStringCount; i++) { byte b; List <byte> name = new List <byte>(); while ((b = br1.ReadByte()) != 0) { name.Add(b); } string material = Encoding.ASCII.GetString(name.ToArray()); material = material.Replace("\0", ""); materialStrings.Add(material); } } br.ReadBytes(32 * unknown5); for (int i = 0; i < 3; i++) { LevelOfDetail LoD = new LevelOfDetail(); LoD.MeshOffset = br.ReadInt16(); LoD.MeshCount = br.ReadInt16(); br.ReadBytes(40); LoD.VertexDataSize = br.ReadInt32(); LoD.IndexDataSize = br.ReadInt32(); LoD.VertexOffset = br.ReadInt32(); LoD.IndexOffset = br.ReadInt32(); modelData.LoD.Add(LoD); } var savePos = br.BaseStream.Position; for (int i = 0; i < modelData.LoD.Count; i++) { List <MeshDataInfo> meshInfoList = new List <MeshDataInfo>(); for (int j = 0; j < modelData.LoD[i].MeshCount; j++) { modelData.LoD[i].MeshList.Add(new Mesh()); meshInfoList.Clear(); br.BaseStream.Seek((i * 136) + 68, SeekOrigin.Begin); var dataBlockNum = br.ReadByte(); while (dataBlockNum != 255) { MeshDataInfo meshInfo = new MeshDataInfo() { VertexDataBlock = dataBlockNum, Offset = br.ReadByte(), DataType = br.ReadByte(), UseType = br.ReadByte() }; meshInfoList.Add(meshInfo); br.ReadBytes(4); dataBlockNum = br.ReadByte(); } modelData.LoD[i].MeshList[j].MeshDataInfoList = meshInfoList.ToArray(); } } br.BaseStream.Seek(savePos, SeekOrigin.Begin); for (int x = 0; x < modelData.LoD.Count; x++) { for (int i = 0; i < modelData.LoD[x].MeshCount; i++) { MeshInfo meshInfo = new MeshInfo() { VertexCount = br.ReadInt32(), IndexCount = br.ReadInt32(), MaterialNum = br.ReadInt16(), MeshPartOffset = br.ReadInt16(), MeshPartCount = br.ReadInt16(), BoneListIndex = br.ReadInt16(), IndexDataOffset = br.ReadInt32() }; for (int j = 0; j < 3; j++) { meshInfo.VertexDataOffsets.Add(br.ReadInt32()); } for (int k = 0; k < 3; k++) { meshInfo.VertexSizes.Add(br.ReadByte()); } meshInfo.VertexDataBlockCount = br.ReadByte(); modelData.LoD[x].MeshList[i].MeshInfo = meshInfo; } } br.ReadBytes(attributeStringCount * 4); br.ReadBytes(unknown6 * 20); for (int i = 0; i < modelData.LoD.Count; i++) { foreach (var mesh in modelData.LoD[i].MeshList) { for (int j = 0; j < mesh.MeshInfo.MeshPartCount; j++) { MeshPart meshPart = new MeshPart() { IndexOffset = br.ReadInt32(), IndexCount = br.ReadInt32(), Attributes = br.ReadInt32(), BoneOffset = br.ReadInt16(), BoneCount = br.ReadInt16() }; mesh.MeshPartList.Add(meshPart); } } } br.ReadBytes(unknown7 * 12); br.ReadBytes(materialStringCount * 4); br.ReadBytes(boneStringCount * 4); for (int i = 0; i < boneListCount; i++) { Bones bones = new Bones(); for (int j = 0; j < 64; j++) { bones.BoneData.Add(br.ReadInt16()); } bones.BoneCount = br.ReadInt32(); modelData.BoneSet.Add(bones); } br.ReadBytes(unknown1 * 16); br.ReadBytes(unknown2 * 12); br.ReadBytes(unknown3 * 4); var boneIndexSize = br.ReadInt32(); for (int i = 0; i < boneIndexSize / 2; i++) { modelData.BoneIndicies.Add(br.ReadInt16()); } int padding = br.ReadByte(); br.ReadBytes(padding); for (int i = 0; i < 4; i++) { ModelMaterial.BoundingBox boundingBox = new ModelMaterial.BoundingBox(); for (int j = 0; j < 4; j++) { boundingBox.PointA.Add(br.ReadSingle()); } for (int k = 0; k < 4; k++) { boundingBox.PointB.Add(br.ReadSingle()); } modelData.BoundingBoxes.Add(boundingBox); } for (int i = 0; i < 3; i++) { for (int j = 0; j < modelData.LoD[i].MeshCount; j++) { Mesh mesh = modelData.LoD[i].MeshList[j]; for (int k = 0; k < mesh.MeshInfo.VertexDataBlockCount; k++) { br.BaseStream.Seek(modelData.LoD[i].VertexOffset + mesh.MeshInfo.VertexDataOffsets[k], SeekOrigin.Begin); mesh.MeshVertexData.Add(br.ReadBytes(mesh.MeshInfo.VertexSizes[k] * mesh.MeshInfo.VertexCount)); } br.BaseStream.Seek(modelData.LoD[i].IndexOffset + (mesh.MeshInfo.IndexDataOffset * 2), SeekOrigin.Begin); mesh.IndexData = br.ReadBytes(2 * mesh.MeshInfo.IndexCount); } } int vertex = 0, coordinates = 0, normals = 0, tangents = 0, colors = 0; for (int i = 0; i < modelData.LoD[0].MeshCount; i++) { objBytes.Clear(); var vertexList = new Vector3Collection(); var texCoordList = new Vector2Collection(); var normalList = new Vector3Collection(); var tangentList = new Vector3Collection(); var colorsList = new Color4Collection(); var indexList = new IntCollection(); Mesh mesh = modelData.LoD[0].MeshList[i]; MeshDataInfo[] meshDataInfoList = mesh.MeshDataInfoList; int c = 0; foreach (var meshDataInfo in meshDataInfoList) { if (meshDataInfo.UseType == 0) { vertex = c; } else if (meshDataInfo.UseType == 3) { normals = c; } else if (meshDataInfo.UseType == 4) { coordinates = c; } else if (meshDataInfo.UseType == 6) { tangents = c; } else if (meshDataInfo.UseType == 7) { colors = c; } c++; } using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[vertex].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[vertex].VertexDataBlock] + meshDataInfoList[vertex].Offset, SeekOrigin.Begin); if (meshDataInfoList[vertex].DataType == 13 || meshDataInfoList[vertex].DataType == 14) { System.Half h1 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h2 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h3 = System.Half.ToHalf((ushort)br1.ReadInt16()); float x = HalfHelper.HalfToSingle(h1); float y = HalfHelper.HalfToSingle(h2); float z = HalfHelper.HalfToSingle(h3); objBytes.Add("v " + x.ToString() + " " + y.ToString() + " " + z.ToString() + " "); vertexList.Add(new Vector3(x, y, z)); } else if (meshDataInfoList[vertex].DataType == 2) { float x = br1.ReadSingle(); float y = br1.ReadSingle(); float z = br1.ReadSingle(); objBytes.Add("v " + x.ToString() + " " + y.ToString() + " " + z.ToString() + " "); vertexList.Add(new Vector3(x, y, z)); } } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[coordinates].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[coordinates].VertexDataBlock] + meshDataInfoList[coordinates].Offset, SeekOrigin.Begin); System.Half h1 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h2 = System.Half.ToHalf((ushort)br1.ReadInt16()); float x = HalfHelper.HalfToSingle(h1); float y = HalfHelper.HalfToSingle(h2); objBytes.Add("vt " + x.ToString() + " " + (y * -1f).ToString() + " "); texCoordList.Add(new Vector2(x, y)); } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[normals].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[normals].VertexDataBlock] + meshDataInfoList[normals].Offset, SeekOrigin.Begin); System.Half h1 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h2 = System.Half.ToHalf((ushort)br1.ReadInt16()); System.Half h3 = System.Half.ToHalf((ushort)br1.ReadInt16()); objBytes.Add("vn " + HalfHelper.HalfToSingle(h1).ToString() + " " + HalfHelper.HalfToSingle(h2).ToString() + " " + HalfHelper.HalfToSingle(h3).ToString() + " "); normalList.Add(new Vector3(HalfHelper.HalfToSingle(h1), HalfHelper.HalfToSingle(h2), HalfHelper.HalfToSingle(h3))); } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[tangents].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[tangents].VertexDataBlock] + meshDataInfoList[tangents].Offset, SeekOrigin.Begin); float x = br1.ReadByte() / 255f; float y = br1.ReadByte() / 255f; float z = br1.ReadByte() / 255f; tangentList.Add(new Vector3(x, y, z)); } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.MeshVertexData[meshDataInfoList[colors].VertexDataBlock]))) { for (int j = 0; j < mesh.MeshInfo.VertexCount; j++) { br1.BaseStream.Seek(j * mesh.MeshInfo.VertexSizes[meshDataInfoList[colors].VertexDataBlock] + meshDataInfoList[colors].Offset, SeekOrigin.Begin); int a = br1.ReadByte(); int r = br1.ReadByte(); int g = br1.ReadByte(); int b = br1.ReadByte(); colorsList.Add(new Color4(r, g, b, a)); } } using (BinaryReader br1 = new BinaryReader(new MemoryStream(mesh.IndexData))) { for (int j = 0; j < mesh.MeshInfo.IndexCount; j += 3) { int i1 = br1.ReadInt16(); int i2 = br1.ReadInt16(); int i3 = br1.ReadInt16(); objBytes.Add("f " + (i1 + 1) + "/" + (i1 + 1) + "/" + (i1 + 1) + " " + (i2 + 1) + "/" + (i2 + 1) + "/" + (i2 + 1) + " " + (i3 + 1) + "/" + (i3 + 1) + "/" + (i3 + 1) + " "); indexList.Add(i1); indexList.Add(i2); indexList.Add(i3); } } ModelMeshData modelMeshData = new ModelMeshData() { Vertices = vertexList, Normals = normalList, TextureCoordinates = texCoordList, Tangents = tangentList, Indices = indexList, VertexColors = colorsList, OBJFileData = objBytes.ToArray() }; meshList.Add(modelMeshData); } } }