// This code example is created for educational purpose
// by Thorsten Thormaehlen (contact: www.thormae.de).
// It is distributed without any warranty.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import com.jogamp.opengl.*;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.util.FPSAnimator;
import com.jogamp.opengl.GL.*;  
import com.jogamp.opengl.GL2.*; 
import com.jogamp.opengl.glu.GLU;

class Renderer {

  private GLU glu = new GLU();

  public float t = 1.0f;
  
  public void init(GLAutoDrawable d) {
    GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context
    gl.glEnable(GL2.GL_DEPTH_TEST);
  }
  public void resize(GLAutoDrawable d, int w, int h) {
    GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context
    gl.glViewport(0, 0, w, h);
    gl.glMatrixMode(GL2.GL_PROJECTION);
    gl.glLoadIdentity();
    glu.gluPerspective (30.0, (double)w/(double)h, 2.0, 20.0);
  }
  
  public void display(GLAutoDrawable d) {
    GL2 gl = d.getGL().getGL2();  // get the OpenGL 2 graphics context
    gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

    gl.glMatrixMode(GL2.GL_MODELVIEW);
    gl.glLoadIdentity();

    // camera orbits in the y=10 plane
    // and looks at origin
    double rad = Math.PI / 180.0f * t;
    glu.gluLookAt(10.0*Math.cos(rad), 10.0 , 10.0*Math.sin(rad), // eye
                  0.0, 0.0, 0.0, // look at
                  0.0, 1.0, 0.0); // up

    //draw model at origin
    //drawCube();
    drawCubeHierarchy(d, 0, 4);
  }

  private void drawCube(GLAutoDrawable d ) {
    GL2 gl = d.getGL().getGL2();  // get the OpenGL 2 graphics context
    
    gl.glColor3f(1.0f,0.0f,0.0f);
    gl.glBegin(GL2.GL_POLYGON);
    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.glColor3f(0.0f,1.0f,0.0f);
    gl.glBegin(GL2.GL_POLYGON);
    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.glColor3f(0.0f,0.0f,1.0f);
    gl.glBegin(GL2.GL_POLYGON);
    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.glColor3f(1.0f,1.0f,0.0f);
    gl.glBegin(GL2.GL_POLYGON);
    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.glColor3f(1.0f,1.0f,1.0f);
    gl.glBegin(GL2.GL_POLYGON);
    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.glColor3f(0.0f,1.0f,1.0f);
    gl.glBegin(GL2.GL_POLYGON);
    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();
  }
  
  private void drawCubeHierarchy(GLAutoDrawable d, int depth, int neighbors) {
    drawCube(d); // draw parent
    depth +=1;
    if (depth < 6){
      for (int n = 0; n < neighbors; n++){
        GL2 gl = d.getGL().getGL2();  // get the OpenGL 2 graphics context
        gl.glPushMatrix();
		gl.glRotatef(n*90.0f-90.0f, 0.0f, 0.0f, 1.0f);
        gl.glTranslatef(2.5f, 0.0f, 0.0f );
        gl.glScalef(0.5f, 0.5f, 0.5f);
        drawCubeHierarchy(d, depth, 3); // draw children
        gl.glPopMatrix();
      }
    }
  }
}

class MyGui extends JFrame implements GLEventListener {

  private Renderer renderer;
  
  public void createGUI() {
    setTitle("Demo for gluLookAt and chains of local transformations");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   
    GLProfile glp = GLProfile.getDefault();
    GLCapabilities caps = new GLCapabilities(glp);
    GLCanvas canvas = new GLCanvas(caps);
    setSize(320, 320);
    
    getContentPane().add(canvas);
    final FPSAnimator ani = new FPSAnimator(canvas, 60, true);
    canvas.addGLEventListener(this);
    setVisible(true);
    renderer = new Renderer();

    ani.start();
  }

  @Override
  public void init(GLAutoDrawable d) { 
    renderer.init(d); 
  }

  @Override
  public void reshape(GLAutoDrawable d, int x, int y, int width, int height) {
    renderer.resize(d, width, height);
  }

  @Override
  public void display(GLAutoDrawable d) {
    float offset = 1.0f;
    renderer.t += offset;
    renderer.display(d);
  }

  @Override
  public void dispose(GLAutoDrawable d) { 
  }

}

public class LookAtLocalTrans {
  public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        MyGui myGUI = new MyGui();
        myGUI.createGUI();
      }
    });
  }
}
