package classwork;

import java.nio.FloatBuffer;
import javax.media.opengl.*;

import jocode.*;

/**
 * GLART_4_matrix_example.java
 *
 * Create a shear matrix to transform the model.  Uses glMultMatrixf() to add a 
 * custom matrix to the MODELVIEW matrix stack.  
 */
public class GLART_4_matrix_example extends JOApp {
    FloatBuffer matrix = allocFloats(16);
    int texture;
    float rotation = 0;
    
    /**
     * Main function just creates and runs the application.
     */
    public static void main(String args[]) {
    	GLART_4_matrix_example app = new GLART_4_matrix_example();
    	displayWidth = 800;
    	displayHeight = 600;
        app.run();
    }

    /**
     * Create a matrix in a FloatBuffer (very much like a float array).
     * This is a "shear" matrix that will tilt the coordinate system to the right.
     * The Y axis shifts .2 units on the X axis for each 1 unit it goes up. 
     */
    public void setup() {
    	/* Shear matrix slants the Y axis to the right */
        makeMatrix( matrix,
              1,      0,      0,      0f,       // X axis 
              
              .2f,    1,      0,      0f,       // Y axis (the X axis shifts .2 to the right for each 1 unit up on the Y axis)
              
              0,      0,      1,      0f,       // Z axis
              
              0,      0,      0,      1f  );    // translation (where is center of coordinate system)

    	/* Identity matrix creates a "plain vanilla" coordinate system
        makeMatrix( matrix,
              1,      0,      0,      0f,       // X axis 
              
              0,      1,      0,      0f,       // Y axis
              
              0,      0,      1,      0f,       // Z axis
              
              0,      0,      0,      1f  );    // translation (where is center of coordinate system)
        */

        /* Reverse perspective
        makeMatrix( matrix,
              1,      0,      0,      0,
              0,      1,      0,      0,
              0,      0,      1,      1,      // this last 1 projects along the Z axis
              0,      0,      0,      1  );
        */
        
        /* Shadow matrix will project the rendered geometry onto the ground plane (Y=0).
         * This creates the appearance of "squashing" shapes flat onto the ground, and 
         * can be used to create a shadow effect.
         */
        /*
        makeMatrix( matrix,
             10.0f,    0.0f,     0.0f,     0.0f,
              5.0f,    0.0f,    -5.0f,    -1.0f,
              0.0f,    0.0f,    10.0f,     0.0f,
              0.0f,    0.0f,     0.0f,    10.0f
        );
        */
        
    	// load and activate a texture for the buildings 
        texture = makeTexture("images/marble.jpg");
        gl.glBindTexture(GL.GL_TEXTURE_2D, texture);
    }

    /**
     * Render the scene.
     */
    public void draw() {
    	rotation += .1f; 
    	
        // Clear screen and depth buffer
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        // Select The Modelview Matrix (controls model orientation)
        gl.glMatrixMode(GL.GL_MODELVIEW);

        // Reset the Modelview matrix
        // this resets the coordinate system to center of screen
        gl.glLoadIdentity();

        // Set the viewpoint
        glu.gluLookAt(
            0f, 1f, 5f,   // eye position
            0f, 0f, 0f,    // target to look at
            0f, 1f, 0f);   // which way is up

        // Multiply current MODELVIEW matrix by our shear matrix.
        // This will merge the shear matrix into the matrix that is currently on the
        // modelview stack so the matrix created by gluLookAt() will still be in effect.
        // Use glLoadMatrix() to replace the matrix (blow away the gluLookAt())
        gl.glMultMatrixf(matrix);

        // draw 10x10 grid centered at origin
        drawGrid();

        gl.glColor3f(.4f, 1f, .4f);
        
        gl.glPushMatrix();
        {
	        gl.glRotatef(rotation, 0,1,0);
	        renderCube();
        }
        gl.glPopMatrix();
        
        // draw background grid after transformations
        drawGrid();
    }

    /**
     * Put the 16 matrix values into a FloatBuffer. fb has to be length 16.
     */
    public FloatBuffer makeMatrix( FloatBuffer fb,
			float m00, float m01, float m02, float m03,
			float m10, float m11, float m12, float m13,
			float m20, float m21, float m22, float m23,
			float m30, float m31, float m32, float m33    ) 
    {
	    fb.put(m00);
	    fb.put(m01);
	    fb.put(m02);
	    fb.put(m03);
	    fb.put(m10);
	    fb.put(m11);
	    fb.put(m12);
	    fb.put(m13);
	    fb.put(m20);
	    fb.put(m21);
	    fb.put(m22);
	    fb.put(m23);
	    fb.put(m30);
	    fb.put(m31);
	    fb.put(m32);
	    fb.put(m33);
	    fb.flip();
	    return fb;
    }

    /**
     *  Draw a 10x10 grid with a crosshair at center
     */
    public void drawGrid() {
    	// draw 10x10 grid
    	gl.glColor3f(.5f, .5f, .5f);
        gl.glLineWidth(1);
        for (int c=-5; c <= 5; c++ ) {
	        gl.glBegin(GL.GL_LINES);
		    	gl.glVertex3f( c, -5f, 0f);        // bottom
		    	gl.glVertex3f( c, 5f, 0f);         // top
			gl.glEnd();
        }
        for (int r=-5; r <= 5; r++ ) {
	        gl.glBegin(GL.GL_LINES);
		    	gl.glVertex3f( -5f, r, 0f);        // left
		    	gl.glVertex3f(  5f, r, 0f);        // right
			gl.glEnd();
        }

        // draw crosshair at origin
    	gl.glColor3f(.8f, .5f, .5f);
        gl.glLineWidth(3);
        gl.glBegin(GL.GL_LINES);
	    	gl.glVertex3f( -1f, 0f, 0f);        // left
	    	gl.glVertex3f( 1f, 0f, 0f);         // right
	    	gl.glVertex3f( 0f, -1f, 0f);        // bottom
	    	gl.glVertex3f( 0f, 1f, 0f);         // top
		gl.glEnd();

		// draw a triangle
		gl.glBegin(GL.GL_TRIANGLES);
		gl.glVertex3f( -.1f, 1f, 0f);		// left bottom
		gl.glVertex3f(  .1f, 1f, 0f);		// rite bottom
		gl.glVertex3f(   0f, 1.1f, 0f);		// top
		gl.glEnd();
    }
}
