package com.framsticks.net.client3D.graphics.loaders;

import java.util.ArrayList;

import pl.vorg.mowa.core.graphics.FloatVertexAttrib;
import pl.vorg.mowa.core.graphics.Geometry;
import pl.vorg.mowa.core.graphics.GeometryGroup;
import pl.vorg.mowa.core.graphics.IndexBuffer;
import pl.vorg.mowa.core.graphics.PrimitiveType;
import pl.vorg.mowa.core.graphics.Vec2;
import pl.vorg.mowa.core.graphics.Vec3;
import pl.vorg.mowa.core.graphics.VertexStream;

import com.framsticks.net.client3D.Log;

/**
 * Klasa zamieniajaca OBJMesh na GeometryGroup, tablice z wierzcholkami na VertexStreamy itp.
 *  
 * @author vorg
 */
//na razie zakladam ze mesh jest jednorodny (tj np z samych trojkatow)
public class OBJMeshConverter {
	public GeometryGroup convert(OBJMesh mesh) {
		Log.getInstance().log("dbg","OBJMeshConverter.convert");
		GeometryGroup group = new GeometryGroup();
		ArrayList<OBJFace> faces = mesh.getFaces();
		
		int faceVertexCount = 0;
		for(OBJFace face : mesh.getFaces()) {
			if (faceVertexCount == 0) {
				faceVertexCount = face.getVertices().length;
			}			
			else if (faceVertexCount != face.getVertices().length) {
				//dwa rozne rodzaje face'ow w jednym meshu
				//trzeba by rozbijac mesha na kilka mniejszych
				Log.getInstance().log("err", "OBJMeshConverter.convert unsupported mesh type" +
						"(faceVertexCount:" + face.getVertices().length + "!=" + faceVertexCount + ")");
				return group;				
			}
		}
		
		//budowanie indeksow
		
		ArrayList<Integer> indexList = new ArrayList<Integer>();
		ArrayList<OBJFaceVertex> faceVertexList = new ArrayList<OBJFaceVertex>();
		
		Geometry geometry = new Geometry();
		
		if (faceVertexCount == 3) {
			geometry.setPrimitiveType(PrimitiveType.Triangles);
		}
		else if (faceVertexCount == 4) {
			geometry.setPrimitiveType(PrimitiveType.Quads);
		}
		else {
			Log.getInstance().log("err", "OBJMeshConverter.convert only triangles and quads are supported (faceVertexCount:" + faceVertexCount + ")");
			return group;
		}
		
		for(int i=0; i<faces.size(); i++) {
			OBJFaceVertex[] faceVertices = faces.get(i).getVertices();
			for(int j=0; j<faceVertexCount; j++) {
				OBJFaceVertex v = faceVertices[j];
				int index = faceVertexList.indexOf(v);
				if (index == -1) {
					faceVertexList.add(v);
					index = faceVertexList.size() - 1;
				}
				indexList.add(index);
			}
		}
		
		VertexStream vertexStream = buildBuffers(mesh, indexList, faceVertexList);
		geometry.setVertexStream(vertexStream);
		
		group.getChildren().add(geometry);
		group.updateBoundingBox();
		
		return group;
	}
	
	private VertexStream buildBuffers(OBJMesh mesh, ArrayList<Integer> indexList, ArrayList<OBJFaceVertex> faceVertexList) {
		VertexStream vertexStream = new VertexStream();
		
		IndexBuffer indexBuffer = new IndexBuffer();		
		int[] idxBuf = new int[indexList.size()];
		for(int i=0; i<indexList.size(); i++) {
			idxBuf[i] = indexList.get(i);
		}
		indexBuffer.setBuffer(idxBuf);
		vertexStream.setIndexBuffer(indexBuffer);
		
		ArrayList<Vec3> vertices = mesh.getVertices();
		FloatVertexAttrib posAttrib = new FloatVertexAttrib("pos");
		float[] posBuf = new float[3*faceVertexList.size()];
		for(int i=0; i<faceVertexList.size(); i++) {
			Vec3 v = vertices.get(faceVertexList.get(i).getVertexIndex());
			posBuf[i*3  ] = v.getX();
			posBuf[i*3+1] = v.getY();
			posBuf[i*3+2] = v.getZ();
		}
		posAttrib.setBuffer(posBuf);
		vertexStream.addAttrib(posAttrib);
		
		ArrayList<Vec3> normals = mesh.getNormals();
		if (normals.size() > 0) {
			FloatVertexAttrib normalAttrib = new FloatVertexAttrib("normal");
			float[] normalBuf = new float[3*faceVertexList.size()];
			for(int i=0; i<faceVertexList.size(); i++) {
				Vec3 v = normals.get(faceVertexList.get(i).getNormalIndex());
				normalBuf[i*3  ] = v.getX();
				normalBuf[i*3+1] = v.getY();
				normalBuf[i*3+2] = v.getZ();
			}
			normalAttrib.setBuffer(normalBuf);
			vertexStream.addAttrib(normalAttrib);
		}
		
		ArrayList<Vec2> texCoords = mesh.getTexCoords();
		if (texCoords.size() > 0) {
			FloatVertexAttrib texCoord0Attrib = new FloatVertexAttrib("texCoord0");
			float[] texCoord0Buf = new float[2*texCoords.size()];
			for(int i=0; i<texCoords.size(); i++) {
				Vec2 tc = texCoords.get(faceVertexList.get(i).getTexCoordIndex());
				texCoord0Buf[i*2  ] = tc.getX();
				texCoord0Buf[i*2+1] = tc.getY();
			}
			texCoord0Attrib.setBuffer(texCoord0Buf);
			vertexStream.addAttrib(texCoord0Attrib);
		}
		
		return vertexStream;
	}
}
