import javax.media.opengl.*;
import javax.media.opengl.glu.*;
import java.awt.*;
import java.awt.event.*;
import com.sun.opengl.util.FPSAnimator;
import java.io.*;

public class JOGLModelLoading implements GLEventListener
{
	private FPSAnimator animator;
	int vertCount = 0,
		faceCount = 0,
		tvertCount = 0;
	Vertex[] v;
	Face[] f;
	TVert[] tv;
	float f_r = 0.0f;	
	
	public JOGLModelLoading()
	{
		Frame frame = new Frame("JOGL test - Polygon");
		GLCanvas canvas = new GLCanvas();
		canvas.addGLEventListener(this);
		frame.add(canvas);
		frame.setSize(500,500);
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e)
			{
				System.exit(0);
			}
		});
		frame.show();
		loadModel();
        animator = new FPSAnimator( canvas, 60 );
        animator.setRunAsFastAsPossible(false);
        animator.start();
	}
	
	public void loadModel()
	{
		FileInputStream fis;
		try
		{
		    fis = new FileInputStream("torus_v2.gm");
		    DataInputStream dis = new DataInputStream(fis);	
	    	String s_Line = dis.readLine(); // Format defination		    
	    	if (s_Line.compareTo("GnosisModel") == 0)
	    	{
	    		System.out.println("Loading GnosisModel...");
	    		s_Line = dis.readLine();
	    		if (Integer.parseInt(s_Line) == 2) // Format version
	    		{
	    			//System.out.println("Format version 2");
	    			s_Line = dis.readLine(); // Model name
	    			//System.out.println("Model name : " + s_Line);
	    			vertCount = Integer.parseInt(dis.readLine()); // Vertex count
	    			//System.out.println("Vertex count : " + vertCount);
	    			faceCount = Integer.parseInt(dis.readLine()); // Face count
	    			//System.out.println("Face count : " + faceCount);
	    			tvertCount = Integer.parseInt(dis.readLine()); // Texture vertex count
	    			//System.out.println("Texture vertex count : " + tvertCount);	    			
	    					    			
	    			v = new Vertex[vertCount];
	    			for (int i=0; i < vertCount; i++) // Vertex data
	    			{
	    				s_Line = dis.readLine();
	    				String[] a = s_Line.split("\\|");	    					    				
	    				v[i] = new Vertex (	Float.parseFloat(a[0]),
	    									Float.parseFloat(a[1]),
	    									Float.parseFloat(a[2]));
	    				//System.out.println("Vertex"+i+" ["+v[i].x+", "+v[i].y+", "+v[i].z+"]");	    				
	    			}
	    			
	    			f = new Face[faceCount];
	    			for (int i=0; i < faceCount; i++)
	    			{
	    				s_Line = dis.readLine();
	    				String a[] = s_Line.split("\\|");
	    				f[i] = new Face	(	Integer.parseInt(a[0]),
	    									Integer.parseInt(a[1]),
	    									Integer.parseInt(a[2]));
	    				//System.out.println("Face"+i+" ["+f[i].a+", "+f[i].b+", "+f[i].c+"]");
	    			}
	    			
	    			tv = new TVert[tvertCount];
	    			for (int i=0; i < tvertCount; i++)
	    			{
	    				s_Line = dis.readLine();
	    				String[] a = s_Line.split("\\|");
	    				tv[i] = new TVert(	Float.parseFloat(a[0]),
	    									Float.parseFloat(a[1]));
	    				//System.out.println("Texture vertex"+i+" ["+tv[i].u+", "+tv[i].v+"]");
	    			}
	    				    			
	    			for (int i=0; i < faceCount; i++)
	    			{
	    				s_Line = dis.readLine();
	    				String[] a = s_Line.split("\\|");
	    				f[i].setTextureFace(Integer.parseInt(a[0]),
	    									Integer.parseInt(a[1]),
	    									Integer.parseInt(a[2]));
	    				//System.out.println("Texture face"+i+" ["+f[i].ta+", "+f[i].tb+", "+f[i].tc+"]");
	    			}
	    			
	    			for (int i=0; i < vertCount; i++)
	    			{
	    				s_Line = dis.readLine();
	    				String[] a = s_Line.split("\\|");
	    				v[i].setNormal(	Float.parseFloat(a[0]),
	    								Float.parseFloat(a[1]),
	    								Float.parseFloat(a[2]));
	    				//System.out.println("Vertex"+i+" normal ["+v[i].n.x+", "+v[i].n.y+", "+v[i].n.z+"]");
	    			}
	    			
	    			for (int i=0; i < faceCount; i++)
	    			{
	    				s_Line = dis.readLine();
	    				String[] a = s_Line.split("\\|");
	    				f[i].setNormal(	Float.parseFloat(a[0]),
	    								Float.parseFloat(a[1]),
	    								Float.parseFloat(a[2]));
	    				//System.out.println("Face"+i+" normal ["+f[i].n.x+", "+f[i].n.y+", "+f[i].n.z+"]");
	    			}	    			
	    		}
	    		System.out.println("Loading done");
	    	}
	    	fis.close();					
		}
		catch (IOException e)
		{
			System.err.println ("Unable to read from file");
			System.exit(-1);
		} 
	}
	
	public void init(GLAutoDrawable drawable)
	{				
		GL gl = drawable.getGL();	    	    
	    gl.glShadeModel(GL.GL_SMOOTH);
	    gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	    gl.glClearDepth(1.0f);
	    gl.glEnable(GL.GL_DEPTH_TEST);
	    gl.glDepthFunc(GL.GL_LEQUAL);
	    gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);	   

	    float[] lightDiffuse = {1.0f, 1.0f, 1.0f, 1.0f};
	    float[] lightAmbient = {0.5f, 0.5f, 0.5f, 1.0f};    
	    float[] lightPosition= {0.0f, 0.0f, 2.0f, 1.0f};

	    gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, lightAmbient, 0);
	    gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, lightDiffuse, 0);
	    gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition, 0);	  
	    gl.glEnable(GL.GL_LIGHT0);
	    gl.glEnable(GL.GL_LIGHTING);
	}
	
	public void display(GLAutoDrawable drawable)
	{
	    GL gl = drawable.getGL();	    
	    gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
	    gl.glLoadIdentity();
	    gl.glTranslatef(0.0f, 0.0f, -200.0f);
	    gl.glRotatef(f_r, 1.0f, 1.0f, 1.0f);	  
	    gl.glBegin(GL.GL_TRIANGLES);
    	for (int i=0; i < f.length; i++)
    	{
    		Face fa = f[i];	     		
    		gl.glNormal3f( v[fa.a-1].n.x, v[fa.a-1].n.y, v[fa.a-1].n.z );    		
    		gl.glVertex3f( v[fa.a-1].x, v[fa.a-1].y, v[fa.a-1].z);
    		gl.glNormal3f( v[fa.b-1].n.x, v[fa.b-1].n.y, v[fa.b-1].n.z );
    		gl.glVertex3f( v[fa.b-1].x, v[fa.b-1].y, v[fa.b-1].z);
    		gl.glNormal3f( v[fa.c-1].n.x, v[fa.c-1].n.y, v[fa.c-1].n.z );
    		gl.glVertex3f( v[fa.c-1].x, v[fa.c-1].y, v[fa.c-1].z);	    		
    	}
	    gl.glEnd();
	    
	    f_r += 1.0f;
	}	
	
	public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h)
	{
		GLU glu = new GLU();
	    GL gl = drawable.getGL();	    
	    gl.glViewport(0,0,w,h);
	    gl.glMatrixMode(GL.GL_PROJECTION);
		gl.glLoadIdentity();
		glu.gluPerspective(45.0f,w/h,1.0f,1000.0f);
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glLoadIdentity();	    
	}	
	
	public void displayChanged(	GLAutoDrawable drawable, 
								boolean modeChanged, 
								boolean deviceChanged)
	{
	}

	public static void main (String[] args)
	{	
		new JOGLModelLoading();
	}
}

class Vertex
{
	float 	x,
			y,
			z;
	Normal n;
	
	public Vertex(float _x, float _y, float _z)
	{
		x = _x;	y = _y;	z = _z;	
	}
	
	public void setVertex(float _x, float _y, float _z)
	{
		x = _x;	y = _y;	z = _z;
	}	
	
	public void setNormal (float _x, float _y, float _z)
	{
		n = new Normal(_x, _y, _z);
	}	
}

class Face
{
	int	a, ta,
		b, tb,
		c, tc;
	Normal n;
	
	public Face(int _a, int _b, int _c)
	{
		a = _a;	b = _b;	c = _c;
	}
	
	public void setFace(int _a, int _b, int _c)
	{
		a = _a;	b = _b;	c = _c;		
	}
	
	public void setTextureFace(int _ta, int _tb, int _tc)
	{
		ta = _ta;
		tb = _tb;
		tc = _tc;
	}
	
	public void setNormal (float _x, float _y, float _z)
	{
		n = new Normal(_x, _y, _z);
	}
}

class TVert
{
	float 	u,
			v;
	
	public TVert(float _u, float _v)
	{
		u = _u;
		v = _v;
	}
	
	public void setTVert(float _u, float _v)
	{
		u = _u;
		v = _v;		
	}
}

class Normal
{
	float 	x,
			y,
			z;
	
	public Normal(float _x, float _y, float _z)
	{
		x = _x;
		y = _y;
		z = _z;
	}
}	
