/**
 * package for utility classes
 */
package simogl.util;

import javax.media.opengl.GL;

/**
 * This class provides some usefull methods for calculations
 * @author Frank Bruns
 *
 */
public class Calc
{
	/**
	 * Returns the sine value for the specified value
	 * @param value value in degrees, not radians
	 * @return sinus
	 */
	public static double sin(double value)
	{
		return Math.sin(Math.toRadians(value));
	}
	
	/**
	 * Returns the cosine value for the specified value
	 * @param value value in degrees, not radians
	 * @return cosine
	 */
	public static double cos(double value)
	{
		return Math.cos(Math.toRadians(value));
	}
	
	/**
	 * Returns the tangent value for the specified value
	 * @param value value in degrees, not radians
	 * @return tangent
	 */
	public static double tan(double value)
	{
		return Math.tan(Math.toRadians(value));
	}
	
	/**
	 * Applies the sphericla billboarding technique by performing
	 * some undo calculations on the current modelview matrix.
	 * The effect of this is that the objects which are drawn 
	 * between the billboardSphericalBegin()- and billboardEnd()-methods 
	 * always face the camera. They even face the camera if you look up
	 * or down, which is the difference to the 
	 * spherical billboarding technique.
	 * @param gl
	 */
	public static void billboardSphericalBegin(GL gl) {
		
		float[] modelviewMatrix = new float[16];
		int i,j;

		// save the current modelview matrix
		gl.glPushMatrix();

		// get the current modelview matrix
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX , modelviewMatrix,0);

		// undo all rotation operation
		for( i=0; i<3; i++ ) 
		    for( j=0; j<3; j++ ) {
			if ( i==j )
			    modelviewMatrix[i*4+j] = 1.0f;
			else
			    modelviewMatrix[i*4+j] = 0.0f;
		    }

		// set the modelview with no rotations
		gl.glLoadMatrixf(modelviewMatrix,0);
	}
	
	/**
	 * Applies the cylindrical billboarding technique by performing
	 * some undo calculations on the current modelview matrix.
	 * The effect of this is that the objects which are drawn 
	 * between the billboardCylindricalBegin()- and billboardEnd()-methods 
	 * always face the camera. But if you look up with the camera 
	 * you will still get a perspective effect, which is the difference 
	 * to the spherical billboarding technique.
	 * @param gl
	 */
	public static void billboardCylindricalBegin(GL gl) {
		
		float[] modelviewMatrix = new float[16];
		int i,j;

		// save the current modelview matrix
		gl.glPushMatrix();

		// get the current modelview matrix
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX , modelviewMatrix,0);

		// undo all rotations made
		for( i=0; i<3; i+=2 )
		{
		    for( j=0; j<3; j++ )
		    {
				if ( i==j ) modelviewMatrix[i*4+j] = 1.0f;
				else modelviewMatrix[i*4+j] = 0.0f;
		    }
		}
		// set the modelview matrix
		gl.glLoadMatrixf(modelviewMatrix,0);
	}
	
	/**
	 * Finishes the application of the current billboarding technique
	 */
	public static void billboardEnd(GL gl) {

		// restore the old modelview matrix
		gl.glPopMatrix();
	}
	
	/**
	 * This method returns a float array with 16 values, that represents
	 * the modelview matrix with all translate operations eliminated.
	 * You can load the matrix with the gl.glLoadMatrixf()-method.
	 * @param gl
	 * @return modelview matrix without its translations
	 */
	public static float[] removeTranslations(GL gl)
	{
		float[] modelview = new float[16];
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, modelview,0);
		
		// set the values for translations to zero
		modelview[12] = 0f;
		modelview[13] = 0f;
		modelview[14] = 0f;
		
		return modelview;
	}
	
	/**
	 * This method returns a float array with 16 values, that represents
	 * the modelview matrix with all rotation operations eliminated.
	 * You can load the matrix with the gl.glLoadMatrixf()-method.
	 * @param gl
	 * @return modelview matrix without its rotations
	 */
	public static float[] removeRotations(GL gl)
	{
		float[] modelview = new float[16];
		gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, modelview,0);
		
		// set the values for translations to zero
		modelview[0] = 0f;
		modelview[2] = 0f;
		modelview[8] = 0f;
		modelview[10] = 0f;
		
		return modelview;
	}
}
