/**
 *  CS 467. Cornell University.
 */

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import net.java.games.jogl.*;
import net.java.games.cg.*;

public class Lambertian extends JFrame implements GLEventListener {
  public static final int VIEWPORT_WIDTH = 512;
  public static final int VIEWPORT_HEIGHT = 512;
  protected GLCanvas canvas;

  // Cg context and profiles
  protected CGcontext cgContext;
  protected int cgVertexProfile;
  protected int cgFragmentProfile;

  // the Cg programs
  protected static CGprogram cgVertexProgram;
  protected static CGprogram cgFragmentProgram;

  // Cg program parameters
  protected static CGparameter cgModelViewProjMatrix;
  protected static CGparameter cgModelViewMatrix;
  protected static CGparameter cgLightPosition;
  protected static CGparameter cgDiffuseColor;

  public Lambertian() {
    super("Simple vertex normal shader");
    setLocation(100, 100);
    setSize(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);

    canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities());
    canvas.addGLEventListener(this);

    JPanel glPanel = new JPanel(new BorderLayout());
    glPanel.add(canvas, BorderLayout.CENTER);
    glPanel.setSize(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
    getContentPane().add(glPanel);

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    show();
  }

  public void display(GLDrawable gLDrawable) {
    final GL gl = gLDrawable.getGL();

    CgGL.cgGLBindProgram(cgVertexProgram);
    CgErrorException.checkCgError();
    CgGL.cgGLBindProgram(cgFragmentProgram);
    CgErrorException.checkCgError();

    // set up the transformation matrices and light position
    CgGL.cgGLSetStateMatrixParameter( cgModelViewProjMatrix, CgGL.CG_GL_MODELVIEW_PROJECTION_MATRIX, CgGL.CG_GL_MATRIX_IDENTITY);
    CgGL.cgGLSetStateMatrixParameter( cgModelViewMatrix, CgGL.CG_GL_MODELVIEW_MATRIX, CgGL.CG_GL_MATRIX_IDENTITY);
    CgGL.cgGLSetParameter3f( cgLightPosition, 10.0f, 15.0f, 5.0f);

    // set the material properties
    CgGL.cgGLSetParameter3f( cgDiffuseColor, 0.9f, 0.1f, 0.7f);

    gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
    gl.glLoadIdentity();

    gl.glBegin(gl.GL_QUADS);

    // Front Face
    gl.glColor3f(0.0f, 0.0f, 1.0f);
    gl.glNormal3f(0.0f,0.0f,1.0f);
    gl.glVertex3f(-1.0f, -1.0f, 1.0f);
    gl.glVertex3f(1.0f, -1.0f, 1.0f);
    gl.glVertex3f(1.0f, 1.0f, 1.0f);
    gl.glVertex3f(-1.0f, 1.0f, 1.0f);

    // Back Face
    //gl.glColor3d(0.0, 0.0, 1.0);
    gl.glNormal3d(0.0,0.0,-1.0);
    gl.glVertex3f( -1.0f, -1.0f, -1.0f);
    gl.glVertex3f( -1.0f, 1.0f, -1.0f);
    gl.glVertex3f(1.0f, 1.0f, -1.0f);
    gl.glVertex3f(1.0f, -1.0f, -1.0f);

    // Top Face
    //gl.glColor3d(0.0, 1.0, 0.0);
    gl.glNormal3d(0.0, 1.0,0.0);
    gl.glVertex3f( -1.0f, 1.0f, -1.0f);
    gl.glVertex3f( -1.0f, 1.0f, 1.0f);
    gl.glVertex3f(1.0f, 1.0f, 1.0f);
    gl.glVertex3f(1.0f, 1.0f, -1.0f);

    // Bottom Face
    gl.glColor3d(0.0, 1.0, 0.0);
    gl.glNormal3d(0.0, -1.0, 0.0);
    gl.glVertex3f( -1.0f, -1.0f, -1.0f);
    gl.glVertex3f(1.0f, -1.0f, -1.0f);
    gl.glVertex3f(1.0f, -1.0f, 1.0f);
    gl.glVertex3f( -1.0f, -1.0f, 1.0f);

    // Right Face
    gl.glColor3d(1.0, 0.0, 0.0);
     gl.glNormal3d(1.0, 0.0, 0.0);
    gl.glVertex3f(1.0f, -1.0f, -1.0f);
    gl.glVertex3f(1.0f, 1.0f, -1.0f);
    gl.glVertex3f(1.0f, 1.0f, 1.0f);
    gl.glVertex3f(1.0f, -1.0f, 1.0f);

    // Left Face
    gl.glColor3d(1.0, 0.0, 0.0);
    gl.glNormal3d(1.0, 0.0, 0.0);
    gl.glVertex3f( -1.0f, -1.0f, -1.0f);
    gl.glVertex3f( -1.0f, -1.0f, 1.0f);
    gl.glVertex3f( -1.0f, 1.0f, 1.0f);
    gl.glVertex3f( -1.0f, 1.0f, -1.0f);

    gl.glEnd();

    //gl.glFlush();
  }

  public void displayChanged(GLDrawable gLDrawable, boolean modeChanged,
                             boolean deviceChanged) {
  }

  public void reshape(GLDrawable gLDrawable, int x, int y, int width,
                      int height) {
    final GL gl = gLDrawable.getGL();
    final GLU glu = gLDrawable.getGLU();

    gl.glViewport(0, 0, width, height);
    gl.glMatrixMode(gl.GL_PROJECTION);
    gl.glLoadIdentity();
    glu.gluPerspective(45.0f, (float) width / (float) height, 0.2f, 100.0f);
    glu.gluLookAt(3.0f, 5.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
    gl.glMatrixMode(gl.GL_MODELVIEW);
    gl.glLoadIdentity();
  }

  public void init(GLDrawable gLDrawable) {
    final GL gl = gLDrawable.getGL();

    gl.glEnable(gl.GL_DEPTH_TEST);

    initializeCg();
}

protected void initializeCg() {
    cgContext = CgGL.cgCreateContext();
    CgErrorException.checkCgError();

    cgVertexProfile = CgGL.CG_PROFILE_VP20;
    cgFragmentProfile = CgGL.CG_PROFILE_FP30;

    CgGL.cgGLEnableProfile( cgVertexProfile);
    CgErrorException.checkCgError();

    CgGL.cgGLEnableProfile( cgFragmentProfile);
    CgErrorException.checkCgError();

    cgVertexProgram  = CgGL.cgCreateProgramFromFile( cgContext, CgGL.CG_SOURCE, "Lambertian.cg", cgVertexProfile, "LamVP", null);
    CgErrorException.checkCgError();

    cgFragmentProgram  = CgGL.cgCreateProgramFromFile( cgContext, CgGL.CG_SOURCE, "Lambertian.cg", cgFragmentProfile, "LamFP", null);
    CgErrorException.checkCgError();

    CgGL.cgGLLoadProgram(cgVertexProgram);
    CgErrorException.checkCgError();

    CgGL.cgGLLoadProgram(cgFragmentProgram);
    CgErrorException.checkCgError();

    cgModelViewProjMatrix = CgGL.cgGetNamedParameter( cgVertexProgram, "modelViewProjMatrix");
    CgErrorException.checkCgError();

    cgModelViewMatrix = CgGL.cgGetNamedParameter( cgVertexProgram, "modelViewMatrix");
    CgErrorException.checkCgError();

    cgLightPosition = CgGL.cgGetNamedParameter( cgVertexProgram, "lightPosition");
    CgErrorException.checkCgError();

    cgDiffuseColor = CgGL.cgGetNamedParameter( cgFragmentProgram, "diffuseColor");
    CgErrorException.checkCgError();

}


  public static void main(String[] args) {
    new Lambertian();
  }
}
