public override void Export(Asset asset, string path) { var model = (asset as Model); var dat = new DAT(); foreach (var mesh in model.Meshes) { var m = new c2Mesh(); foreach (var meshpart in mesh.MeshParts) { m.AddListMaterial((meshpart.Material == null || meshpart.Material.Name == null ? "DEFAULT" : meshpart.Material.Name)); var data = meshpart.IndexBuffer.Data; for (int i = 0; i < data.Count; i += 3) { var v0 = meshpart.VertexBuffer.Data[data[i + 0]]; var v1 = meshpart.VertexBuffer.Data[data[i + 1]]; var v2 = meshpart.VertexBuffer.Data[data[i + 2]]; m.AddFace( new Vector3(v0.Position.X, v0.Position.Y, v0.Position.Z), new Vector3(v1.Position.X, v1.Position.Y, v1.Position.Z), new Vector3(v2.Position.X, v2.Position.Y, v2.Position.Z), new Vector2(v0.UV.X, v0.UV.Y), new Vector2(v1.UV.X, v1.UV.Y), new Vector2(v2.UV.X, v2.UV.Y), m.Materials.Count - 1 ); } } m.Optimise(); m.ProcessMesh(); dat.AddMesh(mesh.Name, 0, m); } dat.Save(path); }
public static void ProcessMOD(string PathIn, string PathOut, cpsxTex[] psxTex, Single scaleFactor, bool bDebug = false, bool bSplit = true) { string pathIn = PathIn.Substring(0, PathIn.LastIndexOf("\\")); string fileIn = PathIn.Replace(pathIn, ""); if (!Directory.Exists(PathOut)) { Directory.CreateDirectory(PathOut); } BinaryReader br = new BinaryReader(new FileStream(pathIn + fileIn, FileMode.Open)); int iMagic = br.ReadInt32(); if (bDebug) { Console.WriteLine("Magic number : " + iMagic); } if (iMagic == 21102604) { // Process map int iBlockCount = br.ReadInt32(); int gX = br.ReadInt32(); int gZ = br.ReadInt32(); int h4 = br.ReadInt32(); if (bDebug) { Console.WriteLine("Block Count : " + iBlockCount + " :: Width : " + gX + " :: Length : " + gZ + " :: H4 : " + h4); } DAT dat = new DAT(); if (bDebug) { Console.WriteLine("Reading 256 4 byte chunks"); } // Possibly some sort of vert colours? for (int i = 0; i < 256; i++) { //Console.WriteLine(i + ")\t" + br.ReadInt32()); br.ReadInt32(); } int iFirstBlockSize = br.ReadInt32(); if (bDebug) { Console.WriteLine("Reading header block"); } int[] blockOffsets = new int[iBlockCount + 1]; for (int i = 0; i < blockOffsets.Length; i++) { blockOffsets[i] = br.ReadInt32(); if (bDebug) { Console.WriteLine("Block start at : " + blockOffsets[i]); } } Console.WriteLine("Reading " + h4 + " records (" + (h4 * 8) + " bytes) of the header block at " + br.BaseStream.Position); // This is similar to the header block in the car files, I have no idea what it is for. for (int i = 0; i < h4; i++) { //Console.WriteLine(i + "\t" + br.ReadInt16() + "\t" + br.ReadInt16() + "\t" + br.ReadInt16() + "\t" + br.ReadByte() + "\t" + br.ReadByte()); br.ReadBytes(8); } Console.WriteLine("Reading " + iFirstBlockSize + " records (" + (iFirstBlockSize * 8) + " bytes) of the first block at " + br.BaseStream.Position); // The first two values are always(?) the same and never repeat. // Material ID lookup int[] matIDs = new int[iFirstBlockSize]; for (int i = 0; i < iFirstBlockSize; i++) { matIDs[i] = br.ReadInt16(); //Console.WriteLine(i + ")\t" + br.ReadInt16() + "\t" + br.ReadUInt16() + "\t" + br.ReadUInt16()); br.ReadBytes(6); } Console.WriteLine("Began seeking at " + br.BaseStream.Position + " of " + br.BaseStream.Length); for (int i = 1; i < blockOffsets.Length; i++) { int z = (i - 1) / gX; int x = (i - 1) - (z * gX); Console.WriteLine(x + ", " + z); if (blockOffsets[i] > 0) { br.BaseStream.Seek(blockOffsets[i], SeekOrigin.Begin); int uAs, uAe, uC, uD, uE, uF; short[] sX = new short[8]; if (bDebug) { Console.WriteLine(); Console.WriteLine("Processing footer for block " + (i - 1)); } uAs = br.ReadInt32(); uAe = br.ReadInt32(); uC = br.ReadInt32(); uD = br.ReadInt32(); if (bDebug) { Console.WriteLine("Block A Start:\t" + uAs); Console.WriteLine("Block A End :\t" + uAe); Console.WriteLine("Offset C :\t" + uC); Console.WriteLine("Offset D :\t" + uD); } for (int j = 0; j < 8; j++) { sX[j] = br.ReadInt16(); if (bDebug) { Console.WriteLine(j + ")\t" + sX[j]); } } uE = br.ReadInt32(); uF = br.ReadInt32(); if (bDebug) { Console.WriteLine("Offset E :\t" + uE); Console.WriteLine("Offset F :\t" + uF); } bool bFlipU = false; if (1 == 1) { c2Mesh m = new c2Mesh(); if (psxTex != null) { for (int j = 0; j < psxTex.Length; j++) { m.AddListMaterial(psxTex[j].Name); } } br.BaseStream.Seek(uAs, SeekOrigin.Begin); Vector3[] verts = new Vector3[sX[0]]; if (bDebug) { Console.WriteLine("Reading " + sX[0] + " records (" + (sX[0] * 8) + " bytes) of block " + (i - 1) + " at " + br.BaseStream.Position); } for (int j = 0; j < sX[0]; j++) { //Single oX = x * -8192; //Single oZ = z * 8192; //verts[j] = new Vector3(-br.ReadInt16() + oX, -br.ReadInt16(), br.ReadInt16() + oZ); //Single oX = x * 8192; //Single oZ = z * 8192; //verts[j] = new Vector3(br.ReadInt16() + oX, -br.ReadInt16(), br.ReadInt16() + oZ); Single oX = x * 8192; Single oZ = z * -8192; verts[j] = new Vector3(br.ReadInt16() + oX, -br.ReadInt16(), -br.ReadInt16() + oZ); // Note: Spare bytes are either 0 0 or 255 255 br.ReadBytes(2); } if (bDebug) { Console.WriteLine("Reading " + sX[2] + " records (" + (sX[2] * 24) + " bytes) of block " + (i - 1) + " at " + br.BaseStream.Position); } for (int j = 0; j < sX[2]; j++) { int v1 = br.ReadInt16(); int v2 = br.ReadInt16(); int v3 = br.ReadInt16(); int v4 = br.ReadInt16(); // This is very occasionally not 0! Single v1u = br.ReadByte(); Single v1v = br.ReadByte(); Single v2u = br.ReadByte(); Single v2v = br.ReadByte(); Single v3u = br.ReadByte(); Single v3v = br.ReadByte(); Single v4u = br.ReadByte(); // This is very occasionally not 0! Single v4v = br.ReadByte(); // This is very occasionally not 0! br.ReadBytes(5); int matID = matIDs[br.ReadByte()]; br.ReadBytes(2); if (psxTex != null) { if (!bFlipU) { v1u /= psxTex[matID].Width; v2u /= psxTex[matID].Width; v3u /= psxTex[matID].Width; } else { v1u = 1.0f - (v1u / psxTex[matID].Width); v2u = 1.0f - (v2u / psxTex[matID].Width); v3u = 1.0f - (v3u / psxTex[matID].Width); } v1v = 1.0f - (v1v / psxTex[matID].Height); v2v = 1.0f - (v2v / psxTex[matID].Height); v3v = 1.0f - (v3v / psxTex[matID].Height); } //Console.WriteLine("Vert #" + v1 + " has UV #" + m.AddUV(new Vector2(v1u, v1v))); //Console.WriteLine("Vert #" + v2 + " has UV #" + m.AddUV(new Vector2(v2u, v2v))); //Console.WriteLine("Vert #" + v3 + " has UV #" + m.AddUV(new Vector2(v3u, v3v))); //m.AddFace(verts[v1], verts[v2], verts[v3], new Vector2(v1u, v1v), new Vector2(v2u, v2v), new Vector2(v3u, v3v), matID); m.AddFace(verts[v3], verts[v2], verts[v1], new Vector2(v3u, v3v), new Vector2(v2u, v2v), new Vector2(v1u, v1v), matID); //m.AddFace(v1, v2, v3, m.AddUV(new Vector2(v1u, v1v)), m.AddUV(new Vector2(v2u, v2v)), m.AddUV(new Vector2(v3u, v3v)), matID); //Console.WriteLine(v1 + " : " + verts[v1].ToString() + " || " + v2 + " : " + verts[v2].ToString() + " || " + v3 + " : " + verts[v3].ToString()); //Console.WriteLine(j + ")\t" + br.ReadByte() + "\t" + br.ReadByte() + "\t" + br.ReadByte() + "\t" + br.ReadByte() + "\t" + br.ReadByte() + "\t" + br.ReadByte() + "\t" + br.ReadInt16()); //br.ReadBytes(10); } if (bDebug) { Console.WriteLine("Reading " + sX[3] + " records (" + (sX[3] * 24) + " bytes) of block " + (i - 1) + " at " + br.BaseStream.Position); } for (int j = 0; j < sX[3]; j++) { // Quads :| int v1 = br.ReadInt16(); int v2 = br.ReadInt16(); int v3 = br.ReadInt16(); int v4 = br.ReadInt16(); Single v1u = br.ReadByte(); Single v1v = br.ReadByte(); Single v2u = br.ReadByte(); Single v2v = br.ReadByte(); Single v3u = br.ReadByte(); Single v3v = br.ReadByte(); Single v4u = br.ReadByte(); Single v4v = br.ReadByte(); br.ReadBytes(5); int matID = matIDs[br.ReadByte()]; br.ReadBytes(2); if (psxTex != null) { if (!bFlipU) { v1u /= psxTex[matID].Width; v2u /= psxTex[matID].Width; v3u /= psxTex[matID].Width; v4u /= psxTex[matID].Width; } else { v1u = 1.0f - (v1u / psxTex[matID].Width); v2u = 1.0f - (v2u / psxTex[matID].Width); v3u = 1.0f - (v3u / psxTex[matID].Width); v4u = 1.0f - (v4u / psxTex[matID].Width); } v1v = 1.0f - (v1v / psxTex[matID].Height); v2v = 1.0f - (v2v / psxTex[matID].Height); v3v = 1.0f - (v3v / psxTex[matID].Height); v4v = 1.0f - (v4v / psxTex[matID].Height); } // correct apart from UVs //m.AddFace(verts[v1], verts[v2], verts[v4], new Vector2(v1u, v1v), new Vector2(v2u, v2v), new Vector2(v4u, v4v), matID); //m.AddFace(verts[v1], verts[v4], verts[v3], new Vector2(v1u, v1v), new Vector2(v4u, v4v), new Vector2(v3u, v3v), matID); // correct apart from UVs //m.AddFace(verts[v1], verts[v2], verts[v4], new Vector2(v1u, v1v), new Vector2(v2u, v2v), new Vector2(v4u, v4v), matID); //m.AddFace(verts[v1], verts[v4], verts[v3], new Vector2(v1u, v1v), new Vector2(v4u, v4v), new Vector2(v3u, v3v), matID); // this is inside out m.AddFace(verts[v4], verts[v2], verts[v1], new Vector2(v4u, v4v), new Vector2(v2u, v2v), new Vector2(v1u, v1v), matID); m.AddFace(verts[v3], verts[v4], verts[v1], new Vector2(v3u, v3v), new Vector2(v4u, v4v), new Vector2(v1u, v1v), matID); //m.AddFace(v1, v2, v4, m.AddUV(new Vector2(v1u, v1v)), m.AddUV(new Vector2(v2u, v2v)), m.AddUV(new Vector2(v4u, v4v)), matID); //m.AddFace(v1, v4, v3, m.AddUV(new Vector2(v1u, v1v)), m.AddUV(new Vector2(v4u, v4v)), m.AddUV(new Vector2(v3u, v3v)), matID); } if (bDebug) { Console.WriteLine("Finished processing section at " + br.BaseStream.Position + " of " + br.BaseStream.Length); } m.ProcessMesh(); if (bDebug) { Console.WriteLine("Adding mesh test" + i); Console.WriteLine(m.Extents.ToString()); } dat.AddMesh("test" + i, 0, m); } } } //dat.CentreOn(0f, 0f, 0f); dat.Scale(scaleFactor); dat.Save(PathOut + fileIn.Replace("MAP", "dat")); } else { // Process everything else int headLoop = br.ReadInt32(); Console.WriteLine("# of offsets " + headLoop); Console.WriteLine("Unknown A " + br.ReadInt32()); Console.WriteLine("Unknown B " + br.ReadInt32()); int iCountA = br.ReadInt32(); Console.WriteLine("There are " + iCountA + " global entries"); for (int i = 0; i < headLoop - 1; i++) { Console.WriteLine("Offset #" + i + " :: " + br.ReadInt32()); } if (br.ReadInt32() != 0) { Console.WriteLine("int not 0"); } Console.WriteLine("Header read at " + br.BaseStream.Position + " of " + br.BaseStream.Length); Console.WriteLine("Reading " + iCountA + " (" + (8 * iCountA) + " bytes) global entries"); for (int i = 0; i < iCountA; i++) { //Console.WriteLine(i + ") " + faceNorms[i].X + " :: " + faceNorms[i].Y + " :: " + faceNorms[i].Z + " :: " + uvScale[i]); br.ReadBytes(8); } DAT dat = new DAT(); while (br.BaseStream.Position < br.BaseStream.Length) { if (bSplit) { dat = new DAT(); } c2Mesh m; Console.WriteLine("Object discovered at " + br.BaseStream.Position + " of " + br.BaseStream.Length); m = new c2Mesh(); if (psxTex != null) { for (int i = 0; i < psxTex.Length; i++) { m.AddListMaterial(psxTex[i].Name); } } int iOffsetC = br.ReadInt32(); int iOffsetD = br.ReadInt32(); int iOffsetE = br.ReadInt32(); Console.WriteLine(iOffsetC + " :: " + iOffsetD + " :: " + iOffsetE); int iCountB = br.ReadInt16(); int iCountC = br.ReadInt16(); Console.WriteLine("There are " + iCountB + " local x entries"); Console.WriteLine("There are " + iCountC + " local y entries"); for (int i = 0; i < 14; i++) { if (br.ReadInt32() != 0) { Console.WriteLine(i + " loop int not 0"); } } string name = ReadString(ref br, 32); Console.WriteLine("Name block :: " + name); Vector3[] verts = new Vector3[iCountB]; for (int i = 0; i < iCountB; i++) { verts[i] = new Vector3(-br.ReadInt16(), -br.ReadInt16(), br.ReadInt16()); //m.AddListVertex(verts[i] * scaleFactor); br.ReadInt16(); } int uvCount = 0; for (int i = 0; i < iCountC; i++) { int v3 = br.ReadInt16(); int v2 = br.ReadInt16(); int v1 = br.ReadInt16(); int faceID = br.ReadInt16(); Single v3u = br.ReadByte(); Single v3v = br.ReadByte(); Single v2u = br.ReadByte(); Single v2v = br.ReadByte(); Single v1u = br.ReadByte(); Single v1v = br.ReadByte(); int unkA = br.ReadInt16(); int unkB = br.ReadInt16(); int matID = br.ReadInt16(); v1u /= psxTex[matID].Width; v2u /= psxTex[matID].Width; v3u /= psxTex[matID].Width; v1v = 1.0f - (v1v / psxTex[matID].Height); v2v = 1.0f - (v2v / psxTex[matID].Height); v3v = 1.0f - (v3v / psxTex[matID].Height); int uv1 = uvCount; m.AddListVertex(verts[v1] * scaleFactor); m.AddListUV(new Vector2(v1u, v1v)); uvCount++; int uv2 = uvCount; m.AddListVertex(verts[v2] * scaleFactor); m.AddListUV(new Vector2(v2u, v2v)); uvCount++; int uv3 = uvCount; m.AddListVertex(verts[v3] * scaleFactor); m.AddListUV(new Vector2(v3u, v3v)); uvCount++; //if (psxTex[matID].Width > psxTex[matID].Height) //{ // Console.WriteLine(i + ") " + v1 + " :: " + v2 + " :: " + v3 + " :: " + faceID + " :: " + v1u + ", " + v1v + " :: " + v2u + ", " + v2v + " :: " + v3u + ", " + v3v + " :: " + unkA + " :: " + unkB + " :: " + matID); // Console.WriteLine(psxTex[matID].Name + " :: " + psxTex[matID].Width + " :: " + psxTex[matID].Height); // Console.WriteLine(m.UVs[uv1].ToString() + " :: " + m.UVs[uv2].ToString() + " :: " + m.UVs[uv3].ToString()); //} m.AddFace(uv1, uv2, uv3, uv1, uv2, uv3, matID); } m.ProcessMesh(); dat.AddMesh(name, 0, m); if (bSplit) { dat.Save(PathOut + fileIn.Replace(".MOD", "_" + name + ".dat").Replace(".COL", ".dat")); } // br.BaseStream.Position = br.BaseStream.Length; } if (!bSplit) { dat.Save(PathOut + fileIn.Replace(".MOD", "_all.dat").Replace(".COL", ".dat")); } } Console.WriteLine(br.BaseStream.Position + " of " + br.BaseStream.Length); br.Close(); }