package com.danitheskunk.skunkworks.gfx.threedee;

import com.danitheskunk.skunkworks.Vec2f;
import com.danitheskunk.skunkworks.Vec3f;
import com.danitheskunk.skunkworks.Vec3i;
import com.danitheskunk.skunkworks.gfx.ITexture;
import org.lwjgl.assimp.AIMesh;

import java.util.ArrayList;
import java.util.List;

public class Mesh {
	private ITexture texture;
	private final List<Vec3i> triangles;
	private final List<Vec2f> uv;
	private final List<Vec3f> vertices;

	public Mesh() {
		vertices = new ArrayList<>();
		triangles = new ArrayList<>();
		uv = new ArrayList<>();
	}

	public static Mesh fromAIMesh(AIMesh aiMesh) {
		var mesh = new Mesh();

		var vertexBuffer = aiMesh.mVertices();
		var faceBuffer = aiMesh.mFaces();
		var texCoordsBuffer = aiMesh.mTextureCoords(0);

		while(vertexBuffer.remaining() > 0) {
			var vert = vertexBuffer.get();
			mesh.addVertex(new Vec3f(vert.x(), vert.y(), vert.z()));
		}

		while(faceBuffer.remaining() > 0) {
			var face = faceBuffer.get();
			if(face.mNumIndices() != 3) {
				throw new RuntimeException("skunkworks only supports " +
					"triangles currently");
			}
			var indices = face.mIndices();
			mesh.addTriangle(indices.get(0), indices.get(1), indices.get(2));
		}

		assert(texCoordsBuffer != null);
		while(texCoordsBuffer.remaining() > 0) {
			var uv = texCoordsBuffer.get();
			var x = Math.max(0.0001, Math.min(uv.x(), 0.9999));
			var y = Math.max(0.0001, Math.min(uv.y(), 0.9999));
			mesh.addUV(new Vec2f(x, 1.0 - y));
		}

		return mesh;
	}

	public void addTriangle(int v1, int v2, int v3) {
		triangles.add(new Vec3i(v1, v2, v3));
	}

	public void addUV(Vec2f uv) {
		this.uv.add(uv);
	}

	public void addVertex(Vec3f vertex) {
		vertices.add(vertex);
	}

	public ITexture getTexture() {
		return texture;
	}

	public Vec3i getTriangle(int idx) {
		return triangles.get(idx);
	}

	public int getTriangleCount() {
		return triangles.size();
	}

	public Vec2f getUV(int idx) {
		return uv.get(idx);
	}

	public Vec3f getVertex(int idx) {
		return vertices.get(idx);
	}

	public void setTexture(ITexture texture) {
		this.texture = texture;
	}
}
