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

import java.nio.FloatBuffer;

import com.jogamp.opengl.GL3;
//import com.jogamp.opengl.GL2; // note here that we don't need to import GL2 
//import com.jogamp.opengl.glu.GLU; // or glu anymore!
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLCanvas;
import javax.swing.JFrame;

import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.util.FPSAnimator;

class Renderer {
 
  private enum VAOs {Triangle, numVAOs};
  private enum VBOs {TriangleAll, numVBOs};
  private int[] vaoID  = new int[VAOs.numVAOs.ordinal()];
  private int[] bufID = new int[VBOs.numVBOs.ordinal()];
  private int triangleVertNo;
  
  public void init(GLAutoDrawable d) {
    GL3 gl = d.getGL().getGL3(); // get the OpenGL 3 graphics context
    gl.glEnable(GL3.GL_DEPTH_TEST);
    
    // create a Vertex Array Objects (VAO)
    gl.glGenVertexArrays(VAOs.numVAOs.ordinal(), vaoID, 0);

    // generate a Vertex Buffer Object (VBO)
    gl.glGenBuffers(VBOs.numVBOs.ordinal(), bufID, 0);

    // binding the Triangle VAO
    gl.glBindVertexArray(vaoID[VAOs.Triangle.ordinal()]);

    float triangleVertexData[] = {
       0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
      -0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
       0.5f,-0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
    };
    triangleVertNo = 3;

    int floatItems = triangleVertNo *(3+4);
    FloatBuffer triangleVertexFB = Buffers.newDirectFloatBuffer(floatItems);
    triangleVertexFB.put(triangleVertexData);
    triangleVertexFB.flip();
    
    gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, bufID[VBOs.TriangleAll.ordinal()]);
    gl.glBufferData(GL3.GL_ARRAY_BUFFER, triangleVertexFB.capacity()*Buffers.SIZEOF_FLOAT, 
                    triangleVertexFB, GL3.GL_STATIC_DRAW);
    

    int stride = (3+4)*Buffers.SIZEOF_FLOAT;
    int offset = 0;

    // position
    int vertexLoc = 0;
    gl.glVertexAttribPointer(vertexLoc, 3, GL3.GL_FLOAT, false, stride, offset);
    gl.glEnableVertexAttribArray(vertexLoc);
  }
 
 
  public void resize(GLAutoDrawable d, int w, int h) {
    GL3 gl = d.getGL().getGL3(); // get the OpenGL 3 graphics context
    gl.glViewport(0, 0, w, h);
  }

  public void display(GLAutoDrawable d) {
    GL3 gl = d.getGL().getGL3();  // get the OpenGL >= 3 graphics context
    
    gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    gl.glClear(GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT);

    // bind Triangle VAO
    gl.glBindVertexArray(vaoID[VAOs.Triangle.ordinal()]);
    // render data
    gl.glDrawArrays(GL3.GL_TRIANGLES, 0, triangleVertNo);

    gl.glFlush();
  }
}

class MyGui extends JFrame implements GLEventListener {

  private Renderer renderer;

  public void createGUI() {
    setTitle("First OpenGL 3 Forward Compatible Example");
    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) {
    renderer.display(d);
  }

  @Override
  public void dispose(GLAutoDrawable d) {
  }
}

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