/// <summary> /// Create a Mesh, with found props /// </summary> /// <param name="positions"></param> /// <param name="textureCoordinates"></param> /// <param name="triangleIndices"></param> /// <param name="normals"></param> /// <param name="tangents"></param> /// <param name="bitangents"></param> /// <param name="material"></param> /// <param name="transforms"></param> private void CreateMesh(Vector3Collection positions, Vector2Collection textureCoordinates, IntCollection triangleIndices, List <Matrix> transforms, out Vector3Collection normals, out Vector3Collection tangents, out Vector3Collection bitangents, MaterialCore material) { ComputeNormals(positions, triangleIndices, out normals); if (textureCoordinates == null) { textureCoordinates = new Vector2Collection(); foreach (var pos in positions) { textureCoordinates.Add(Vector2.One); } } MeshBuilder.ComputeTangents(positions, normals, textureCoordinates, triangleIndices, out tangents, out bitangents); MeshGeometry3D mesh = new MeshGeometry3D() { Positions = positions, Normals = normals, TextureCoordinates = textureCoordinates, Indices = triangleIndices, Tangents = tangents, BiTangents = bitangents }; Object3D ob3d = new Object3D(); ob3d.Geometry = mesh; ob3d.Material = material; ob3d.Transform = transforms; ob3d.Name = "Default"; this.obGroup.Add(ob3d); }
private static List <MeshGeometryModel3D> GenerateMeshGeometryModels(MGEOFile mgeo) { List <MeshGeometryModel3D> models = new List <MeshGeometryModel3D>(mgeo.Objects.Count); foreach (MGEOObject mgeoModel in mgeo.Objects) { IntCollection indices = new IntCollection(mgeoModel.Indices.Select(x => (int)x).AsEnumerable()); Vector3Collection vertices = new Vector3Collection(mgeoModel.Vertices.Count); Vector2Collection uvs = new Vector2Collection(mgeoModel.Vertices.Count); foreach (MGEOVertex vertex in mgeoModel.Vertices) { vertices.Add(new dxVector3(vertex.Position.X, vertex.Position.Y, vertex.Position.Z)); uvs.Add(new dxVector2(vertex.DiffuseUV.X, vertex.DiffuseUV.Y)); } MeshGeometry3D meshGeometry = new MeshGeometry3D() { Indices = indices, Positions = vertices, TextureCoordinates = uvs }; MeshGeometryModel3D model = new MeshGeometryModel3D() { Geometry = meshGeometry, Material = DiffuseMaterials.Pearl, Name = mgeoModel.Name }; models.Add(model); } return(models); }
public static MeshGeometry3D GetRect(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) { var positions = new Vector3Collection(); var triangleIndices = new HelixToolkit.Wpf.SharpDX.Core.IntCollection(); var normals = new Vector3Collection(); //private Vector3Collection tangents; //private Vector3Collection bitangents; var textureCoordinates = new Vector2Collection(); var widthOrientation = new Vector3(0, 0, 1); var heightOrientation = new Vector3(0, 1, 0); positions.Add(p0); positions.Add(p1); positions.Add(p2); positions.Add(p3); normals.Add(new Vector3(1, 0, 0)); normals.Add(new Vector3(1, 0, 0)); normals.Add(new Vector3(1, 0, 0)); normals.Add(new Vector3(1, 0, 0)); textureCoordinates.Add(new Vector2(0, 0)); textureCoordinates.Add(new Vector2(1, 0)); textureCoordinates.Add(new Vector2(1, 1)); textureCoordinates.Add(new Vector2(0, 1)); triangleIndices.Add(2); triangleIndices.Add(1); triangleIndices.Add(0); triangleIndices.Add(0); triangleIndices.Add(3); triangleIndices.Add(2); return(new MeshGeometry3D() { Positions = positions, Indices = triangleIndices, Normals = normals, TextureCoordinates = textureCoordinates }); }
public static MeshGeometry3D GetRect(Vector3 center, float width, float height, Vector3 widthOrientation, Vector3 heightOrientation) { var positions = new Vector3Collection(); var triangleIndices = new HelixToolkit.Wpf.SharpDX.Core.IntCollection(); var normals = new Vector3Collection(); //private Vector3Collection tangents; //private Vector3Collection bitangents; var textureCoordinates = new Vector2Collection(); positions.Add(center - widthOrientation * width / 2 - heightOrientation * height / 2); positions.Add(center + widthOrientation * width / 2 - heightOrientation * height / 2); positions.Add(center + widthOrientation * width / 2 + heightOrientation * height / 2); positions.Add(center - widthOrientation * width / 2 + heightOrientation * height / 2); normals.Add(new Vector3(1, 0, 0)); normals.Add(new Vector3(1, 0, 0)); normals.Add(new Vector3(1, 0, 0)); normals.Add(new Vector3(1, 0, 0)); textureCoordinates.Add(new Vector2(1, 1)); textureCoordinates.Add(new Vector2(0, 1)); textureCoordinates.Add(new Vector2(0, 0)); textureCoordinates.Add(new Vector2(1, 0)); triangleIndices.Add(2); triangleIndices.Add(1); triangleIndices.Add(0); triangleIndices.Add(0); triangleIndices.Add(3); triangleIndices.Add(2); return(new MeshGeometry3D() { Positions = positions, Indices = triangleIndices, Normals = normals, TextureCoordinates = textureCoordinates }); }
private Vector2Collection ReadTexCoords(BinaryReader reader) { int size = reader.ReadUInt16(); var pts = new Vector2Collection(); for (int i = 0; i < size; i++) { float x = reader.ReadSingle(); float y = reader.ReadSingle(); pts.Add(new Vector2(x, 1 - y)); } return(pts); }
private void CreatePerlinNoise() { float[] noise; MathHelper.GenerateNoiseMap(Width, Height, 8, out noise); Vector2Collection collection = new Vector2Collection(Width * Height); for (int i = 0; i < Width; ++i) { for (int j = 0; j < Height; ++j) { collection.Add(new Vector2(Math.Abs(noise[Width * i + j]), 0)); } } Model.TextureCoordinates = collection; }
public static IEnumerable <GroupNode> LoadMapMGEO(MGEOFile mgeo, MapData mapData, string mapPath) { foreach (MGEOObject mgeoModel in mgeo.Objects) { IntCollection indices = new IntCollection(mgeoModel.Indices.Select(x => (int)x).AsEnumerable()); Vector3Collection vertices = new Vector3Collection(mgeoModel.Vertices.Count); Vector2Collection uvs = new Vector2Collection(mgeoModel.Vertices.Count); foreach (MGEOVertex vertex in mgeoModel.Vertices) { vertices.Add(new dxVector3(vertex.Position.X, vertex.Position.Y, vertex.Position.Z)); uvs.Add(new dxVector2(vertex.DiffuseUV.X, vertex.DiffuseUV.Y)); } foreach (MGEOSubmesh submesh in mgeoModel.Submeshes) { GroupNode groupNode = new GroupNode() { Name = mgeoModel.Name }; MeshGeometry3D submeshGeometry3D = new MeshGeometry3D() { Indices = indices.GetRange((int)submesh.StartIndex, (int)submesh.IndexCount) as IntCollection, Positions = vertices, TextureCoordinates = uvs }; DiffuseMaterial diffuseMaterial = new DiffuseMaterial() { Name = submesh.Material, DiffuseMap = CreateMaterial(submesh.Material, mapData, mapPath), EnableUnLit = true }; groupNode.AddChildNode(new MeshNode() { Name = mgeoModel.Name + "|" + submesh.Material, Geometry = submeshGeometry3D, Material = diffuseMaterial }); yield return(groupNode); } } }
public static Vector2Collection Parse(string source) { IFormatProvider formatProvider = CultureInfo.InvariantCulture; var th = new TokenizerHelper(source, formatProvider); var resource = new Vector2Collection(); Vector2 value; while (th.NextToken()) { value = new Vector2( Convert.ToSingle(th.GetCurrentToken(), formatProvider), Convert.ToSingle(th.NextTokenRequired(), formatProvider)); resource.Add(value); } return(resource); }
public static MeshGeometry3D GetCube(Vector3 minimum, Vector3 maximum) { var positions = new Vector3Collection(); var triangleIndices = new HelixToolkit.Wpf.SharpDX.Core.IntCollection(); var normals = new Vector3Collection(); var textureCoordinates = new Vector2Collection(); positions.Add(new Vector3(minimum.X, minimum.Y, minimum.Z)); //0 positions.Add(new Vector3(maximum.X, minimum.Y, minimum.Z)); //1 positions.Add(new Vector3(minimum.X, maximum.Y, minimum.Z)); //2 positions.Add(new Vector3(minimum.X, minimum.Y, maximum.Z)); //3 positions.Add(new Vector3(maximum.X, maximum.Y, minimum.Z)); //4 positions.Add(new Vector3(maximum.X, minimum.Y, maximum.Z)); //5 positions.Add(new Vector3(minimum.X, maximum.Y, maximum.Z)); //6 positions.Add(new Vector3(maximum.X, maximum.Y, maximum.Z)); //7 triangleIndices.AddRange(new[] { 0, 5, 3, 0, 1, 5 }); triangleIndices.AddRange(new[] { 1, 7, 5, 1, 4, 7 }); triangleIndices.AddRange(new[] { 4, 7, 2, 7, 6, 2 }); triangleIndices.AddRange(new[] { 6, 3, 0, 6, 0, 2 }); triangleIndices.AddRange(new[] { 6, 3, 5, 5, 7, 6 }); triangleIndices.AddRange(new[] { 0, 1, 2, 2, 1, 4 }); for (int i = 0; i < positions.Count; i++) { normals.Add(new Vector3(1, 0, 0)); textureCoordinates.Add(new Vector2(0, 0)); } return(new MeshGeometry3D() { Positions = positions, Indices = triangleIndices, Normals = normals, TextureCoordinates = textureCoordinates }); }
///////////////////////////////////////////////////////////////////////////////////////////// //// below all functions taken from "Helix 3D Toolkit" MeshBuilder ///////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Gets a circle section (cached). /// </summary> /// <param name="thetaDiv"> /// The number of division. /// </param> /// <returns> /// A circle. /// </returns> public static IList<Vector2> GetCircle(int thetaDiv) { IList<Vector2> circle; if (!CircleCache.TryGetValue(thetaDiv, out circle)) { circle = new Vector2Collection(); CircleCache.Add(thetaDiv, circle); for (int i = 0; i < thetaDiv; i++) { double theta = Math.PI * 2 * ((double)i / (thetaDiv - 1)); circle.Add(new Vector2((float)Math.Cos(theta), -(float)Math.Sin(theta))); } } return circle; }
private static void AppendSphere(Vector3 center, double radius, int thetaSteps, int phiSteps, out Vector3Collection positions, out Vector3Collection normals, out Vector2Collection textureCoordinates, out IntCollection triangleIndices) { positions = new Vector3Collection(); normals = new Vector3Collection(); textureCoordinates = new Vector2Collection(); triangleIndices = new IntCollection(); double dt = DegToRad(360.0) / thetaSteps; double dp = DegToRad(180.0) / phiSteps; for (int pi = 0; pi <= phiSteps; pi++) { double phi = pi * dp; for (int ti = 0; ti <= thetaSteps; ti++) { // we want to start the mesh on the x axis double theta = ti * dt; positions.Add(GetPosition(theta, phi, radius) + center); normals.Add(GetNormal(theta, phi)); textureCoordinates.Add(GetTextureCoordinate(theta, phi)); } } for (int pi = 0; pi < phiSteps; pi++) { for (int ti = 0; ti < thetaSteps; ti++) { int x0 = ti; int x1 = ti + 1; int y0 = pi * (thetaSteps + 1); int y1 = (pi + 1) * (thetaSteps + 1); triangleIndices.Add(x0 + y0); triangleIndices.Add(x0 + y1); triangleIndices.Add(x1 + y0); triangleIndices.Add(x1 + y0); triangleIndices.Add(x0 + y1); triangleIndices.Add(x1 + y1); } } }
/// <summary> /// Adds a (possibly hollow) pipe. /// </summary> /// <param name="point1"> /// The start point. /// </param> /// <param name="point2"> /// The end point. /// </param> /// <param name="innerDiameter"> /// The inner diameter. /// </param> /// <param name="diameter"> /// The outer diameter. /// </param> /// <param name="thetaDiv"> /// The number of divisions around the pipe. /// </param> public void AddPipe(Vector3 point1, Vector3 point2, double innerDiameter, double diameter, int thetaDiv) { var dir = point2 - point1; double height = dir.Length(); dir.Normalize(); var pc = new Vector2Collection { new Vector2(0, (float)innerDiameter / 2), new Vector2(0, (float)diameter / 2), new Vector2((float)height, (float)diameter / 2), new Vector2((float)height, (float)innerDiameter / 2) }; if (innerDiameter > 0) { // Add the inner surface pc.Add(new Vector2(0, (float)innerDiameter / 2)); } this.AddRevolvedGeometry(pc, point1, dir, thetaDiv); }
/// <summary> /// Adds a (possibly truncated) cone. /// </summary> /// <param name="origin"> /// The origin. /// </param> /// <param name="direction"> /// The direction (normalization not required). /// </param> /// <param name="baseRadius"> /// The base radius. /// </param> /// <param name="topRadius"> /// The top radius. /// </param> /// <param name="height"> /// The height. /// </param> /// <param name="baseCap"> /// Include a base cap if set to <c>true</c> . /// </param> /// <param name="topCap"> /// Include the top cap if set to <c>true</c> . /// </param> /// <param name="thetaDiv"> /// The number of divisions around the cone. /// </param> /// <remarks> /// See http://en.wikipedia.org/wiki/Cone_(geometry). /// </remarks> public void AddCone( Vector3 origin, Vector3 direction, double baseRadius, double topRadius, double height, bool baseCap, bool topCap, int thetaDiv) { var pc = new Vector2Collection(); if (baseCap) { pc.Add(new Vector2(0, 0)); } pc.Add(new Vector2(0, (float)baseRadius)); pc.Add(new Vector2((float)height, (float)topRadius)); if (topCap) { pc.Add(new Vector2((float)height, 0)); } this.AddRevolvedGeometry(pc, origin, direction, thetaDiv); }
/// <summary> /// Gets a circle segment section. /// </summary> /// <param name="thetaDiv">The number of division.</param> /// <param name="totalAngle">The angle of the circle segment.</param> /// <param name="angleOffset">The angle-offset to use.</param> /// <returns> /// A circle segment. /// </returns> public static IList<Vector2> GetCircleSegment(int thetaDiv, float totalAngle = 2 * (float)Math.PI, float angleOffset = 0) { IList <Vector2> circleSegment; circleSegment = new Vector2Collection(); for (int i = 0; i < thetaDiv; i++) { double theta = totalAngle * ((double)i / (thetaDiv - 1)) + angleOffset; circleSegment.Add(new Vector2((float)Math.Cos(theta), (float)Math.Sin(theta))); } return circleSegment; }
/// <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 Vector2Collection ReadTexCoords(BinaryReader reader) { int size = reader.ReadUInt16(); var pts = new Vector2Collection(); for(int i=0;i< size; i++) { float x = reader.ReadSingle(); float y = reader.ReadSingle(); pts.Add(new Vector2(x, y)); } return pts; }
/// <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); } } }
public static Dictionary <string, object> PlaneMesh( [DefaultArgument("CoordinateSystem.ByOriginVectors(Point.Origin(), Vector.XAxis(), Vector.YAxis())")] CoordinateSystem cs, [DefaultArgument("20.0")] double lengthX, [DefaultArgument("20.0")] double lengthY, [DefaultArgument("20")] int divX, [DefaultArgument("20")] int divY, [DefaultArgument("true")] bool alternatingDiagons) { if (divX < 1 || divY < 0) { throw new Exception("divX and divY must be larger than 0"); } List <Point> vertices = new List <Point>((divX + 1) * (divY + 1)); Vector2Collection textureCoordinates = new Vector2Collection(); for (int j = 0; j <= divY; j++) { for (int i = 0; i <= divX; i++) { vertices.Add( Point.ByCartesianCoordinates( cs, ((double)i / divX - 0.5f) * lengthX, ((double)j / divY - 0.5f) * lengthY)); textureCoordinates.Add(new Vector2((float)i / (float)(divX), 1f - (float)j / (float)(divY))); } } List <int> indices = new List <int>(); List <List <int> > quadFaceVertexIndices = new List <List <int> >(); for (int j = 0; j < divY; j++) { for (int i = 0; i < divX; i++) { int a = i + j * (divX + 1); int b = i + 1 + j * (divX + 1); int c = i + 1 + (j + 1) * (divX + 1); int d = i + (j + 1) * (divX + 1); quadFaceVertexIndices.Add(new List <int> { a, b, c, d }); if (alternatingDiagons) { if ((i + j) % 2 == 0) { indices.Add(a); indices.Add(b); indices.Add(c); indices.Add(a); indices.Add(c); indices.Add(d); } else { indices.Add(a); indices.Add(b); indices.Add(d); indices.Add(b); indices.Add(c); indices.Add(d); } } else { indices.Add(a); indices.Add(b); indices.Add(c); indices.Add(a); indices.Add(c); indices.Add(d); } } } return(new Dictionary <string, object>() { { "mesh", Mesh.ByVerticesAndIndices(vertices, indices) }, { "quadFaceVertexIndices", quadFaceVertexIndices }, { "textureCoordinates", new TextureCoordinateSet(textureCoordinates) }, }); }
///////////////////////////////////////////////////////////////////////////////////////////// //// below all functions taken from "Helix 3D Toolkit" MeshBuilder ///////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Gets a circle section (cached). /// </summary> /// <param name="thetaDiv"> /// The number of division. /// </param> /// <param name="closed"> /// Is the circle closed? /// If true, the last point will not be at the same position than the first one. /// </param> /// <returns> /// A circle. /// </returns> public static IList<Vector2> GetCircle(int thetaDiv, bool closed = false) { IList<Vector2> circle = null; // If the circle can't be found in one of the two caches if ((!closed && !CircleCache.TryGetValue(thetaDiv, out circle)) || (closed && !ClosedCircleCache.TryGetValue(thetaDiv, out circle))) { circle = new Vector2Collection(); // Add to the cache if (!closed) { CircleCache.TryAdd(thetaDiv, circle); } else { ClosedCircleCache.TryAdd(thetaDiv, circle); } // Determine the angle steps var num = closed ? thetaDiv : thetaDiv - 1; for (int i = 0; i < thetaDiv; i++) { double theta = Math.PI * 2 * ((double)i / num); circle.Add(new Vector2((float)Math.Cos(theta), (float)-Math.Sin(theta))); } } // Since Vector2Collection is not Freezable, // return new IList<Vector> to avoid manipulation of the Cached Values IList<Vector2> result = new List<Vector2>(); foreach (var point in circle) { result.Add(new Vector2(point.X, point.Y)); } return result; }
/// <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); } } }
/// <summary> /// Create a Mesh, with found props /// </summary> /// <param name="positions"></param> /// <param name="textureCoordinates"></param> /// <param name="triangleIndices"></param> /// <param name="normals"></param> /// <param name="tangents"></param> /// <param name="bitangents"></param> /// <param name="material"></param> private void CreateMesh(Vector3Collection positions, Vector2Collection textureCoordinates, IntCollection triangleIndices, out Vector3Collection normals, out Vector3Collection tangents, out Vector3Collection bitangents,Material material) { ComputeNormals(positions, triangleIndices, out normals); if (textureCoordinates == null) { textureCoordinates = new Vector2Collection(); foreach(var pos in positions) { textureCoordinates.Add(Vector2.One); } } MeshBuilder.ComputeTangents(positions, normals, textureCoordinates, triangleIndices, out tangents, out bitangents); MeshGeometry3D mesh = new MeshGeometry3D() { Positions = positions, Normals = normals, TextureCoordinates = textureCoordinates, Indices = triangleIndices, Tangents = tangents, BiTangents = bitangents }; Object3D ob3d = new Object3D(); ob3d.Geometry = mesh; ob3d.Material = material; ob3d.Transform = Matrix.Identity; ob3d.Name = "Default"; this.obGroup.Add(ob3d); }