// /home/epsilon/Projects/Asteroid/ABot/Framework1/GLVisualizer/GLAsteroid.cs created with MonoDevelop
// User: epsilon at 21:35 20.04.2008
//

using System;
using GLUtils;
using Tao.OpenGl;


namespace GLVisualizer
{
	public class GLAsteroid : GLUtils.GLObject
	{
		public enum AsteroidType {Small = 0, Medium = 1, Large = 2};
		
		// fields
		//--------
		private AsteroidType theAsteroidType = AsteroidType.Small;
		private static int theBaseDisplayList;
		private static bool theIsCompiled = false;
		
		
        // constructor: position, size
        public GLAsteroid(Vector3 position, Vector3 size)
			: base (position, size)
        {
			this.Color = new Vector3(0.75f, 0.25f, 0.25f);
        }

        // constructor: position
        public GLAsteroid(Vector3 position)
            : base(position)
		{
			this.Color = new Vector3(0.75f, 0.25f, 0.25f);
		}
		
		public GLAsteroid()
			: base()
		{
			this.Color = new Vector3(0.75f, 0.25f, 0.25f);
		}
		
		public override void Draw()
		{
            Gl.glLoadIdentity(); // Reset The Current Modelview Matrix
            Gl.glTranslatef(thePosition.X, thePosition.Y, thePosition.Z);


			// color and texture
			//-------------------
			if (theUseAlphaBlending)
            {
                Gl.glEnable(Gl.GL_BLEND);
                Gl.glColor4f(theColor.X, theColor.Y, theColor.Z, theAlphaBlending);
            }
            else
            {
                Gl.glDisable(Gl.GL_BLEND);
                Gl.glColor3f(theColor.X, theColor.Y, theColor.Z);
            }

            // XYZ-rotation
            // rotation angle must be given in degrees
            Gl.glRotatef((float)(180.0 / Math.PI * theRotation.X), 1.0f, 0.0f, 0.0f);
            Gl.glRotatef((float)(180.0 / Math.PI * theRotation.Y), 0.0f, 1.0f, 0.0f);
            Gl.glRotatef((float)(180.0 / Math.PI * theRotation.Z), 0.0f, 0.0f, 1.0f);

			if (!theIsCompiled)
			{
				// create display list for each asteroid size
				theBaseDisplayList = Gl.glGenLists(3);

				Gl.glNewList(theBaseDisplayList + (int)AsteroidType.Small, Gl.GL_COMPILE);
				this.Compile(AsteroidType.Small);
				Gl.glEndList();
				
				Gl.glNewList(theBaseDisplayList + (int)AsteroidType.Medium, Gl.GL_COMPILE);
				this.Compile(AsteroidType.Medium);
				Gl.glEndList();

				Gl.glNewList(theBaseDisplayList + (int)AsteroidType.Large, Gl.GL_COMPILE);
				this.Compile(AsteroidType.Large);
				Gl.glEndList();

				theIsCompiled = true;
			}

			Gl.glCallList(theBaseDisplayList + (int)this.theAsteroidType);
			
			Gl.glDisable(Gl.GL_BLEND);			
		}

		private void Compile(AsteroidType type)
		{
			this.theSize = Visualizer.theSmallAsteroidSize;
			if (type == AsteroidType.Medium)
				this.theSize = Visualizer.theMediumAsteroidSize;
			if (type == AsteroidType.Large)
				this.theSize = Visualizer.theLargeAsteroidSize;
			
			// use demanded texture
            int textureAddress = GLScreen.GetTextureAddress(theTexture);

			// if demanded texture does not exist, use empty texture
			if (textureAddress == -1)
				GLScreen.UnbindTexture();
			else
			{
				Gl.glBindTexture(Gl.GL_TEXTURE_2D, textureAddress);
                Gl.glColor3f(1.0f, 1.0f, 1.0f);
			}
				
			Gl.glBegin(Gl.GL_TRIANGLE_STRIP); // draw a cube/diamond using a triangle strip
            {
				Gl.glTexCoord2f(0.0f, 0.0f);
				Gl.glVertex3f(-0.5f * theSize.X, 0.0f * theSize.Y, 0.0f); // left corner
                Gl.glTexCoord2f(1.0f, 0.0f);
                Gl.glVertex3f(0.0f * theSize.X, 0.5f * theSize.Y, 0.0f); // upper corner
                Gl.glTexCoord2f(1.0f, 1.0f);
                Gl.glVertex3f(0.0f * theSize.X, 0.0f * theSize.Y, 0.5f * theSize.Z); // top				
                Gl.glTexCoord2f(0.0f, 1.0f);
                Gl.glVertex3f(0.5f * theSize.X, 0.0f * theSize.Y, 0.0f); // right corner
				Gl.glTexCoord2f(0.0f, 0.0f);
                Gl.glVertex3f(0.0f * theSize.X, -0.5f * theSize.Y, 0.0f); // lower corner
                Gl.glTexCoord2f(1.0f, 0.0f);
                Gl.glVertex3f(0.0f * theSize.X, 0.0f * theSize.Y, -0.5f * theSize.Z); // bottom				
                Gl.glTexCoord2f(1.0f, 1.0f);
                Gl.glVertex3f(-0.5f * theSize.X, 0.0f * theSize.Y, 0.0f); // left corner
                Gl.glTexCoord2f(0.0f, 1.0f);
                Gl.glVertex3f(0.0f * theSize.X, 0.5f * theSize.Y, 0.0f); // upper corner
            }
            Gl.glEnd();	// done drawing the triangle strip

            Gl.glBegin(Gl.GL_TRIANGLES); // draw the missing triangles
            {
                Gl.glTexCoord2f(1.0f, 0.0f);
                Gl.glVertex3f(-0.5f * theSize.X, 0.0f * theSize.Y, 0.0f); // left corner
                Gl.glTexCoord2f(0.0f, 1.0f);
                Gl.glVertex3f(0.0f * theSize.X, -0.5f * theSize.Y, 0.0f); // lower corner
                Gl.glTexCoord2f(1.0f, 1.0f);
                Gl.glVertex3f(0.0f * theSize.X, 0.0f * theSize.Y, 0.5f * theSize.Z); // top				

                Gl.glTexCoord2f(1.0f, 0.0f);
				Gl.glVertex3f(0.5f * theSize.X, 0.0f * theSize.Y, 0.0f); // right corner
                Gl.glTexCoord2f(0.0f, 1.0f);
                Gl.glVertex3f(0.0f * theSize.X, 0.5f * theSize.Y, 0.0f); // upper corner
                Gl.glTexCoord2f(0.0f, 0.0f);
                Gl.glVertex3f(0.0f * theSize.X, 0.0f * theSize.Y, -0.5f * theSize.Z); // bottom				
            }
            Gl.glEnd();	// done drawing the triangles
		}
		
		private void CalculateRotationFromPosition()
		{
			// just some random coefficients
			this.Rotation.X = 0.7f*this.Position.X + 1.3f*this.Position.Y + 1.9f*this.Position.Z;
			this.Rotation.Y = 1.6f*this.Position.X + 0.3f*this.Position.Y + 1.1f*this.Position.Z;
			this.Rotation.Z = 1.0f*this.Position.X + 1.8f*this.Position.Y + 0.6f*this.Position.Z;
		}

		public void UpdateProperties(Framework1.Asteroid asteroid)
		{
			// position asteroid
			this.Position.X = ((float)asteroid.Position.X + Visualizer.theOffsetX)/Visualizer.theScale;
			this.Position.Y = ((float)asteroid.Position.Y + Visualizer.theOffsetY)/Visualizer.theScale;
			this.Position.Z = Visualizer.thePlayfieldZ;
					
			this.theAsteroidType = AsteroidType.Large;
			if (asteroid.HitRadius == 14)
				this.theAsteroidType = AsteroidType.Small;
			if (asteroid.HitRadius == 15)
				this.theAsteroidType = AsteroidType.Medium;
			
			this.CalculateRotationFromPosition();
		}
	}
}
