using System.Globalization; using OpenTK.Mathematics; namespace Engine.Asset.Mesh.Loader; public class ObjMeshLoader : IMeshLoader { private static readonly ObjMeshLoader Instance = new(); public static Mesh Load(string path, MeshLoaderParameters parameters = MeshLoaderParameters.Default) => Instance.LoadMesh(path, parameters); public Mesh LoadMesh(string path, MeshLoaderParameters parameters = MeshLoaderParameters.Default) { var mesh = new Mesh(); var tempVertices = new List(); var tempNormals = new List(); var tempUVs = new List(); var index = 0u; var loadNormals = parameters.HasFlag(MeshLoaderParameters.LoadNormals); var loadUVs = parameters.HasFlag(MeshLoaderParameters.LoadUVs); using var reader = new StreamReader(path); while (reader.ReadLine() is { } line) { var parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 0 || parts[0].StartsWith('#')) continue; switch (parts[0]) { case "v": tempVertices.Add(new Vector3( float.Parse(parts[1], CultureInfo.InvariantCulture), float.Parse(parts[2], CultureInfo.InvariantCulture), float.Parse(parts[3], CultureInfo.InvariantCulture) )); break; case "vt" when loadUVs: tempUVs.Add(new Vector2( float.Parse(parts[1], CultureInfo.InvariantCulture), float.Parse(parts[2], CultureInfo.InvariantCulture) )); break; case "vn" when loadNormals: tempNormals.Add(new Vector3( float.Parse(parts[1], CultureInfo.InvariantCulture), float.Parse(parts[2], CultureInfo.InvariantCulture), float.Parse(parts[3], CultureInfo.InvariantCulture) )); break; case "f": for (var i = 1; i <= 3; i++) { var faceComponents = parts[i].Split('/'); var meshVertex = new Mesh.Vertex { Position = tempVertices[int.Parse(faceComponents[0]) - 1] }; if (loadUVs && faceComponents.Length > 1 && faceComponents[1] != "") { meshVertex.Uv = tempUVs[int.Parse(faceComponents[1]) - 1]; } if (loadNormals && faceComponents.Length > 2 && faceComponents[2] != "") { meshVertex.Normal = tempNormals[int.Parse(faceComponents[2]) - 1]; } mesh.VerticesInternal.Add(meshVertex); mesh.IndicesInternal.Add(index++); } break; } } if (parameters.HasFlag(MeshLoaderParameters.Optimize)) mesh = IMeshLoader.Optimize(mesh); return mesh; } }