package k8.util;
import k8.SceneNode;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
public final class Camera extends SceneNode
{
// The single instance of the Camera
private static Camera instance = null;
// Field of view (x-axis)
private int fov;
// Determines field of view (y-axis)
private float aspectRatio;
// Near clipping plane distance
private float nearClip;
// Far clipping plane distance
private float farClip;
/**
* Gets the Camera instance.
*/
public static Camera getInstance()
{
if (instance == null)
instance = new Camera();
return instance;
}
/** Enforce Singleton. */
private Camera()
{
// Default at 40 degrees field of view (x-axis)
fov = 40;
// Default aspect ratio of the window
DisplayMode dm = Display.getDisplayMode();
aspectRatio = dm.getWidth() / dm.getHeight();
// Default clipping planes (always positive, near never less than 0.1)
nearClip = 1f;
farClip = 10000;
setProjectionMatrix();
}
/** Sets the field of view (x-axis) */
public void setFOV(int fov)
{
this.fov = fov;
setProjectionMatrix();
}
/** Gets the field of view (x-axis) */
public int getFOV()
{
return fov;
}
/** Sets the aspect ratio */
public void setAspectRatio(float ratio)
{
aspectRatio = ratio;
setProjectionMatrix();
}
/** Gets the aspect ratio. Use to determine fov on y-axis. */
public float getAspectRatio()
{
return aspectRatio;
}
/** Sets the near clipping plane distance */
public void setNearClip(float nearClip)
{
this.nearClip = nearClip;
setProjectionMatrix();
}
/** Gets the near clipping plane distance */
public float getNearClip()
{
return nearClip;
}
/** Sets the far clipping plane distance */
public void setFarClip(float farClip)
{
this.farClip = farClip;
setProjectionMatrix();
}
/** Gets the far clipping plane distance */
public float getFarClip()
{
return farClip;
}
/**
* Sets the perspective projection matrix
*/
private void setProjectionMatrix()
{
float radians = (float) (fov / 2 * Math.PI / 180);
float deltaZ = farClip - nearClip;
float sine = (float) Math.sin(radians);
float cotangent = (float) Math.cos(radians) / sine;
// Sanity check
if ((deltaZ == 0) || (sine == 0) || (aspectRatio == 0)) {
return;
}
// Select the projection matrix
GL11.glMatrixMode(GL11.GL_PROJECTION);
// Reset the projection matrix
GL11.glLoadIdentity();
// Set the projection matrix to use perspective
Matrix.makeIdentity(Matrix.matrix);
Matrix.matrix.put(0 * 4 + 0, cotangent / aspectRatio);
Matrix.matrix.put(1 * 4 + 1, cotangent);
Matrix.matrix.put(2 * 4 + 2, - (farClip + nearClip) / deltaZ);
Matrix.matrix.put(2 * 4 + 3, -1);
Matrix.matrix.put(3 * 4 + 2, -2 * nearClip * farClip / deltaZ);
Matrix.matrix.put(3 * 4 + 3, 0);
GL11.glMultMatrix(Matrix.matrix);
// Select the modelview matrix
GL11.glMatrixMode(GL11.GL_MODELVIEW);
}
@Override
protected void transform()
{
Matrix.makeIdentity(Matrix.matrix);
Matrix.matrix.put(0 * 4 + 0, this.T[0]);
Matrix.matrix.put(1 * 4 + 0, this.T[4]);
Matrix.matrix.put(2 * 4 + 0, this.T[8]);
Matrix.matrix.put(0 * 4 + 1, this.T[1]);
Matrix.matrix.put(1 * 4 + 1, this.T[5]);
Matrix.matrix.put(2 * 4 + 1, this.T[9]);
Matrix.matrix.put(0 * 4 + 2, this.T[2]);
Matrix.matrix.put(1 * 4 + 2, this.T[6]);
Matrix.matrix.put(2 * 4 + 2, this.T[10]);
GL11.glLoadIdentity();
GL11.glMultMatrix(Matrix.matrix);
GL11.glTranslated(-this.T[3], -this.T[7], -this.T[11]);
}
}