1
mirror of https://github.com/sampletext32/ParkanPlayground.git synced 2025-12-12 01:31:20 +04:00
Files
parkan-playground/ParkanPlayground/MshConverter.cs

240 lines
8.7 KiB
C#
Raw Normal View History

using System.Buffers.Binary;
2025-08-23 19:03:03 +03:00
using System.Text;
using Common;
using NResLib;
namespace ParkanPlayground;
public class MshConverter
{
public void Convert(string mshPath)
{
var mshNresResult = NResParser.ReadFile(mshPath);
var mshNres = mshNresResult.Archive!;
using var mshFs = new FileStream(mshPath, FileMode.Open, FileAccess.Read, FileShare.Read);
2025-08-26 04:29:30 +03:00
var component01 = Msh01.ReadComponent(mshFs, mshNres);
var component02 = Msh02.ReadComponent(mshFs, mshNres);
var component0A = Msh0A.ReadComponent(mshFs, mshNres);
var component07 = Msh07.ReadComponent(mshFs, mshNres);
var component0D = Msh0D.ReadComponent(mshFs, mshNres);
var component06 = Msh06.ReadComponent(mshFs, mshNres);
var component03 = Read03Component(mshFs, mshNres);
2025-08-23 19:03:03 +03:00
2025-08-26 04:29:30 +03:00
// --- Write OBJ ---
using var sw = new StreamWriter("test.obj", false, Encoding.UTF8);
2025-08-26 04:29:30 +03:00
foreach (var v in component03)
sw.WriteLine($"v {v.X:F8} {v.Y:F8} {v.Z:F8}");
2025-08-26 04:29:30 +03:00
var vertices = new List<Vector3>();
var faces = new List<(int, int, int)>(); // store indices into vertices list
2025-08-26 04:29:30 +03:00
for (var pieceIndex = 0; pieceIndex < component01.Elements.Count; pieceIndex++)
{
2025-08-26 04:29:30 +03:00
var piece = component01.Elements[pieceIndex];
var state = (piece.State00 == 0xffff) ? 0 : piece.State00;
2025-08-26 04:29:30 +03:00
var mesh02Element = component02.Elements[state];
2025-08-26 04:29:30 +03:00
int indexInto07 = mesh02Element.StartIndexIn07;
2025-08-26 04:29:30 +03:00
var element0Dstart = mesh02Element.StartOffsetIn0d;
var element0Dcount = mesh02Element.ByteLengthIn0D;
2025-08-26 04:29:30 +03:00
Console.WriteLine($"Started piece {pieceIndex}. State={state}. 0D start={element0Dstart}, count={element0Dcount}");
2025-08-26 04:29:30 +03:00
for (var comp0Dindex = 0; comp0Dindex < element0Dcount; comp0Dindex++)
{
var element0D = component0D[element0Dstart + comp0Dindex];
2025-08-23 19:03:03 +03:00
2025-08-26 04:29:30 +03:00
var indexInto03 = element0D.IndexInto03;
var indexInto06 = element0D.IndexInto06;
var count = (uint)element0D.number_of_triangles;
// Convert IndexInto06 to ushort array index (3 ushorts per triangle)
Console.WriteLine(
$"Processing 0D element[{element0Dstart + comp0Dindex}]. IndexInto03={indexInto03}, IndexInto06={indexInto06}. Number of triangles={count}");
if (count != 0)
{
sw.WriteLine($"o piece_{pieceIndex++}_of_mesh_{comp0Dindex}");
if (count % 3 != 0)
{
Console.WriteLine("Number of triangles is not multiple of 3");
_ = 5;
}
count = (count + 2) / 3; // number of triangles
for (int tri = 0; tri < count; tri++)
{
// Each triangle uses 3 consecutive ushorts in component06
var comp07 = component07[indexInto07];
var i1 = indexInto03 + component06[indexInto06];
var i2 = indexInto03 + component06[indexInto06 + 1];
var i3 = indexInto03 + component06[indexInto06 + 2];
var v1 = component03[i1];
var v2 = component03[i2];
var v3 = component03[i3];
sw.WriteLine($"f {i1 + 1} {i2 + 1} {i3 + 1}");
// push vertices to global list
vertices.Add(v1);
vertices.Add(v2);
vertices.Add(v3);
int baseIndex = vertices.Count;
// record face (OBJ is 1-based indexing!)
faces.Add((baseIndex - 2, baseIndex - 1, baseIndex));
indexInto07++;
indexInto06 += 3; // step by 3 since each triangle uses 3 ushorts
}
_ = 5;
}
}
2025-08-23 19:03:03 +03:00
}
2025-08-26 04:29:30 +03:00
}
public record Face(Vector3 P1, Vector3 P2, Vector3 P3);
public static void ExportCube(string filePath, Vector3[] points)
{
if (points.Length != 8)
throw new ArgumentException("Cube must have exactly 8 points.");
2025-08-23 19:03:03 +03:00
2025-08-26 04:29:30 +03:00
using (StreamWriter writer = new StreamWriter(filePath))
2025-08-23 19:03:03 +03:00
{
2025-08-26 04:29:30 +03:00
// Write vertices
foreach (var p in points)
2025-08-23 19:03:03 +03:00
{
2025-08-26 04:29:30 +03:00
writer.WriteLine($"v {p.X} {p.Y} {p.Z}");
2025-08-23 19:03:03 +03:00
}
2025-08-26 04:29:30 +03:00
// Write faces (each face defined by 4 vertices, using 1-based indices)
int[][] faces = new int[][]
{
new int[] { 1, 2, 3, 4 }, // bottom
new int[] { 5, 6, 7, 8 }, // top
new int[] { 1, 2, 6, 5 }, // front
new int[] { 2, 3, 7, 6 }, // right
new int[] { 3, 4, 8, 7 }, // back
new int[] { 4, 1, 5, 8 } // left
};
foreach (var f in faces)
2025-08-23 19:03:03 +03:00
{
2025-08-26 04:29:30 +03:00
writer.WriteLine($"f {f[0]} {f[1]} {f[2]} {f[3]}");
2025-08-23 19:03:03 +03:00
}
}
2025-08-26 04:29:30 +03:00
}
public static void ExportCubesAtPositions(string filePath, List<Vector3> centers, float size = 2f)
{
float half = size / 2f;
using (StreamWriter writer = new StreamWriter(filePath))
2025-08-23 19:03:03 +03:00
{
2025-08-26 04:29:30 +03:00
int vertexOffset = 0;
2025-08-23 19:03:03 +03:00
2025-08-26 04:29:30 +03:00
foreach (var c in centers)
{
// Generate 8 vertices for this cube
Vector3[] vertices = new Vector3[]
{
new Vector3(c.X - half, c.Y - half, c.Z - half),
new Vector3(c.X + half, c.Y - half, c.Z - half),
new Vector3(c.X + half, c.Y - half, c.Z + half),
new Vector3(c.X - half, c.Y - half, c.Z + half),
new Vector3(c.X - half, c.Y + half, c.Z - half),
new Vector3(c.X + half, c.Y + half, c.Z - half),
new Vector3(c.X + half, c.Y + half, c.Z + half),
new Vector3(c.X - half, c.Y + half, c.Z + half)
};
// Write vertices
foreach (var v in vertices)
{
writer.WriteLine($"v {v.X} {v.Y} {v.Z}");
}
// Define faces (1-based indices, counter-clockwise)
int[][] faces = new int[][]
{
new int[] { 1, 2, 3, 4 }, // bottom
new int[] { 5, 6, 7, 8 }, // top
new int[] { 1, 2, 6, 5 }, // front
new int[] { 2, 3, 7, 6 }, // right
new int[] { 3, 4, 8, 7 }, // back
new int[] { 4, 1, 5, 8 } // left
};
// Write faces with offset
foreach (var f in faces)
{
writer.WriteLine(
$"f {f[0] + vertexOffset} {f[1] + vertexOffset} {f[2] + vertexOffset} {f[3] + vertexOffset}");
}
vertexOffset += 8;
}
}
2025-08-23 19:03:03 +03:00
}
2025-08-26 04:29:30 +03:00
private static List<Vector3> Read03Component(FileStream mshFs, NResArchive mshNres)
2025-08-23 19:03:03 +03:00
{
2025-08-26 04:29:30 +03:00
var verticesFileEntry = mshNres.Files.FirstOrDefault(x => x.FileType == "03 00 00 00");
2025-08-23 19:03:03 +03:00
2025-08-26 04:29:30 +03:00
if (verticesFileEntry is null)
2025-08-23 19:03:03 +03:00
{
2025-08-26 04:29:30 +03:00
throw new Exception("Archive doesn't contain vertices file (03)");
2025-08-23 19:03:03 +03:00
}
2025-08-26 04:29:30 +03:00
if (verticesFileEntry.ElementSize != 12)
2025-08-23 19:03:03 +03:00
{
2025-08-26 04:29:30 +03:00
throw new Exception("Vertices file (03) element size is not 12");
}
2025-08-23 19:03:03 +03:00
var verticesFile = new byte[verticesFileEntry.ElementCount * verticesFileEntry.ElementSize];
mshFs.Seek(verticesFileEntry.OffsetInFile, SeekOrigin.Begin);
mshFs.ReadExactly(verticesFile, 0, verticesFile.Length);
var vertices = verticesFile.Chunk(12).Select(x => new Vector3(
BinaryPrimitives.ReadSingleLittleEndian(x.AsSpan(0)),
BinaryPrimitives.ReadSingleLittleEndian(x.AsSpan(4)),
BinaryPrimitives.ReadSingleLittleEndian(x.AsSpan(8))
)
).ToList();
return vertices;
}
2025-08-26 04:29:30 +03:00
void Export(string filePath, IEnumerable<Vector3> vertices, List<IndexedEdge> edges)
{
using (var writer = new StreamWriter(filePath))
{
writer.WriteLine("# Exported OBJ file");
// Write vertices
foreach (var v in vertices)
{
writer.WriteLine($"v {v.X:F2} {v.Y:F2} {v.Z:F2}");
}
// Write edges as lines ("l" elements in .obj format)
foreach (var e in edges)
{
// OBJ uses 1-based indexing
writer.WriteLine($"l {e.Index1 + 1} {e.Index2 + 1}");
}
}
}
}