package com.hypixel.hytale.builtin.buildertools.objimport;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class ObjParser {
private ObjParser() {
}
@Nonnull
public static ObjMesh parse(@Nonnull Path path) throws IOException, ObjParseException {
List<float[]> vertices = new ArrayList();
List<float[]> uvCoordinates = new ArrayList();
List<int[]> faces = new ArrayList();
List<int[]> faceUvIndices = new ArrayList();
List<String> faceMaterials = new ArrayList();
String mtlLib = null;
String currentMaterial = null;
BufferedReader reader = Files.newBufferedReader(path);
try {
int lineNum = 0;
String line;
while((line = reader.readLine()) != null) {
++lineNum;
line = line.trim();
if (!line.isEmpty() && !line.startsWith("#")) {
String[] parts = line.split("\\s+");
if (parts.length != 0) {
switch (parts[0]) {
case "v":
parseVertex(parts, vertices, lineNum);
break;
case "vt":
parseUvCoordinate(parts, uvCoordinates, lineNum);
break;
case "f":
int faceCountBefore = faces.size();
parseFace(parts, faces, faceUvIndices, uvCoordinates.size(), lineNum);
int facesAdded = faces.size() - faceCountBefore;
for(int i = 0; i < facesAdded; ++i) {
faceMaterials.add(currentMaterial);
}
break;
case "mtllib":
if (parts.length > 1) {
mtlLib = parts[1].trim();
}
break;
case "usemtl":
if (parts.length > 1) {
currentMaterial = parts[1].trim();
}
}
}
}
}
} catch (Throwable var18) {
if (reader != null) {
try {
reader.close();
} catch (Throwable var17) {
var18.addSuppressed(var17);
}
}
throw var18;
}
if (reader != null) {
reader.close();
}
if (vertices.isEmpty()) {
throw new ObjParseException("OBJ file contains no vertices");
} else if (faces.isEmpty()) {
throw new ObjParseException("OBJ file contains no faces");
} else {
return new ObjMesh(vertices, uvCoordinates, faces, faceUvIndices, faceMaterials, mtlLib);
}
}
private static void parseVertex(String[] parts, List<float[]> vertices, int lineNum) throws ObjParseException {
if (parts.length < 4) {
throw new ObjParseException("Invalid vertex at line " + lineNum + ": expected at least 3 coordinates");
} else {
try {
float x = Float.parseFloat(parts[1]);
float y = Float.parseFloat(parts[2]);
float z = Float.parseFloat(parts[3]);
vertices.add(new float[]{x, y, z});
} catch (NumberFormatException var6) {
throw new ObjParseException("Invalid vertex coordinates at line " + lineNum);
}
}
}
private static void parseUvCoordinate(String[] parts, List<float[]> uvCoordinates, int lineNum) throws ObjParseException {
if (parts.length < 3) {
throw new ObjParseException("Invalid UV coordinate at line " + lineNum + ": expected at least 2 values");
} else {
try {
float u = Float.parseFloat(parts[1]);
float v = Float.parseFloat(parts[2]);
uvCoordinates.add(new float[]{u, v});
} catch (NumberFormatException var5) {
throw new ObjParseException("Invalid UV coordinates at line " + lineNum);
}
}
}
private static void parseFace(String[] parts, List<int[]> faces, List<int[]> faceUvIndices, int uvCount, int lineNum) throws ObjParseException {
if (parts.length < 4) {
throw new ObjParseException("Invalid face at line " + lineNum + ": expected at least 3 vertices");
} else {
int[] vertexIndices = new int[parts.length - 1];
int[] uvIndices = new int[parts.length - 1];
boolean hasUvs = false;
for(int i = 1; i < parts.length; ++i) {
String vertexData = parts[i];
String[] components = vertexData.split("/");
try {
int vIndex = Integer.parseInt(components[0]);
vertexIndices[i - 1] = vIndex > 0 ? vIndex - 1 : vIndex;
} catch (NumberFormatException var13) {
throw new ObjParseException("Invalid face vertex index at line " + lineNum);
}
if (components.length >= 2 && !components[1].isEmpty()) {
try {
int uvIndex = Integer.parseInt(components[1]);
uvIndices[i - 1] = uvIndex > 0 ? uvIndex - 1 : uvIndex + uvCount;
hasUvs = true;
} catch (NumberFormatException var12) {
uvIndices[i - 1] = -1;
}
} else {
uvIndices[i - 1] = -1;
}
}
if (vertexIndices.length == 3) {
faces.add(vertexIndices);
faceUvIndices.add(hasUvs ? uvIndices : null);
} else if (vertexIndices.length == 4) {
faces.add(new int[]{vertexIndices[0], vertexIndices[1], vertexIndices[2]});
faces.add(new int[]{vertexIndices[0], vertexIndices[2], vertexIndices[3]});
if (hasUvs) {
faceUvIndices.add(new int[]{uvIndices[0], uvIndices[1], uvIndices[2]});
faceUvIndices.add(new int[]{uvIndices[0], uvIndices[2], uvIndices[3]});
} else {
faceUvIndices.add((Object)null);
faceUvIndices.add((Object)null);
}
} else {
for(int i = 1; i < vertexIndices.length - 1; ++i) {
faces.add(new int[]{vertexIndices[0], vertexIndices[i], vertexIndices[i + 1]});
if (hasUvs) {
faceUvIndices.add(new int[]{uvIndices[0], uvIndices[i], uvIndices[i + 1]});
} else {
faceUvIndices.add((Object)null);
}
}
}
}
}
public static record ObjMesh(List<float[]> vertices, List<float[]> uvCoordinates, List<int[]> faces, List<int[]> faceUvIndices, List<String> faceMaterials, @Nullable String mtlLib) {
public float[] getBounds() {
float minX = 3.4028235E38F;
float minY = 3.4028235E38F;
float minZ = 3.4028235E38F;
float maxX = -3.4028235E38F;
float maxY = -3.4028235E38F;
float maxZ = -3.4028235E38F;
for(float[] v : this.vertices) {
minX = Math.min(minX, v[0]);
minY = Math.min(minY, v[1]);
minZ = Math.min(minZ, v[2]);
maxX = Math.max(maxX, v[0]);
maxY = Math.max(maxY, v[1]);
maxZ = Math.max(maxZ, v[2]);
}
return new float[]{minX, minY, minZ, maxX, maxY, maxZ};
}
public float getHeight() {
float[] bounds = this.getBounds();
return bounds[4] - bounds[1];
}
public boolean hasMaterials() {
return this.mtlLib != null && !this.faceMaterials.isEmpty() && this.faceMaterials.stream().anyMatch((m) -> m != null);
}
public boolean hasUvCoordinates() {
return !this.uvCoordinates.isEmpty() && this.faceUvIndices.stream().anyMatch((uv) -> uv != null);
}
public void transformZUpToYUp() {
for(float[] v : this.vertices) {
float y = v[1];
float z = v[2];
v[1] = z;
v[2] = -y;
}
}
public void transformXUpToYUp() {
for(float[] v : this.vertices) {
float x = v[0];
float y = v[1];
v[0] = y;
v[1] = x;
}
}
}
public static class ObjParseException extends Exception {
public ObjParseException(String message) {
super(message);
}
}
}