import java.io.IOException;
import java.nio.FloatBuffer;

import javax.media.opengl.DebugGL3;
import javax.media.opengl.GL3;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;

import com.jogamp.common.nio.Buffers;
import com.jogamp.newt.event.WindowAdapter;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.opengl.util.glsl.ShaderCode;
import com.jogamp.opengl.util.glsl.ShaderProgram;

public class GL3TestAttrib implements GLEventListener {
	private ShaderProgram program;

	public static void main(String[] args) {
		GL3TestAttrib app = new GL3TestAttrib();
		app.run();
	}

	public void run() {
		final GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GL3));
		caps.setBackgroundOpaque(true);
		final GLWindow glWindow = GLWindow.create(caps);
		glWindow.setTitle("Corridors");
		glWindow.setSize(640, 480);
		glWindow.setUndecorated(false);
		glWindow.setPointerVisible(true);
		glWindow.addGLEventListener(this);
		glWindow.addWindowListener(new WindowAdapter() {

			@Override
			public void windowDestroyed(WindowEvent event) {
				glWindow.setVisible(false);
				System.exit(0);
			}
		});
		glWindow.setVisible(true);
	}

	@Override
	public void init(GLAutoDrawable drawable) {
		if (drawable.getGL().isGL3()) {
			final GL3 gl3 = drawable.getGL().getGL3();
			drawable.setGL(new DebugGL3(gl3));
		} else {
			System.err.println("Not a GL3 drawable");
			System.exit(1);
		}
	}

	@Override
	public void dispose(GLAutoDrawable drawable) {
	}

	@Override
	public void display(GLAutoDrawable drawable) {
		final float[] vertices = { 0.0f, 0.7f, 0.0f, 0.0f, 0.1f, 0.0f, 0.9f, 0.1f, 0.0f };

		GL3 gl = drawable.getGL().getGL3();
		gl.glClearColor(1, 0, 1, 0.5f); // Purple
		gl.glClear(GL3.GL_STENCIL_BUFFER_BIT | GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT);
		try {
			int positionAttribute = loadShaderProgram(gl);

			gl.glUseProgram(program.program());

			gl.glEnableVertexAttribArray(positionAttribute);
			FloatBuffer fbVertices = Buffers.newDirectFloatBuffer(vertices);
			gl.glVertexAttribPointer(positionAttribute, 3, GL3.GL_FLOAT, false, 0, fbVertices);

			gl.glDrawArrays(GL3.GL_TRIANGLES, 0, 3);

			// Allow release of vertex position and color memory
			gl.glDisableVertexAttribArray(positionAttribute);

			gl.glUseProgram(0);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
	}

	private int loadShaderProgram(final GL3 gl) throws IOException {
		final String nameBase = "sample";
		final String filePrefix = "/shaders/" + nameBase;

		/*
		 * #version 150 core
		 * 
		 * in vec3 attribute_Position;
		 * 
		 * void main(void) { gl_Position = vec4(attribute_Position, 1.0); }
		 */
		ShaderCode vertexShader = ShaderCode.create(gl, GL3.GL_VERTEX_SHADER, getClass(), filePrefix, "/tmp", nameBase,
				false);
		final boolean vertexCompile = vertexShader.compile(gl);
		if (!vertexCompile) {
			throw new RuntimeException("Unable to compile vertex shader: " + nameBase);
		}

		/*
		 * #version 150 core
		 * 
		 * out vec4 fragColor ;
		 * 
		 * void main (void) { fragColor = vec4(1.0f, 1.0f, 1.0f, 0.5f); }
		 */
		ShaderCode fragmentShader = ShaderCode.create(gl, GL3.GL_FRAGMENT_SHADER, getClass(), filePrefix, "/tmp",
				nameBase, false);
		final boolean fragmentCompile = fragmentShader.compile(gl);
		if (!fragmentCompile) {
			throw new RuntimeException("Unable to compile fragment shader: " + nameBase);
		}
		program = new ShaderProgram();
		program.init(gl);

		program.add(vertexShader);
		program.add(fragmentShader);

		program.link(gl, System.out);

		final boolean validateProgram = program.validateProgram(gl, System.out);
		if (!validateProgram) {
			throw new RuntimeException("Shader program did not validate: " + nameBase);
		}

		int attribPosition = gl.glGetAttribLocation(program.program(), "attribute_Position");
		return attribPosition;
	}
}