package net.virtuallyabstract.demo1

import javax.media.opengl._
import javax.media.opengl.awt._
import javax.media.opengl.fixedfunc._
import com.jogamp.newt.event.awt._
import com.jogamp.opengl.util._
import com.jogamp.opengl.util.glsl._;
import java.util._
import java.awt._
import java.awt.event._
import javax.swing._
import scala.io._
import java.nio._;


object ShaderLoader
{
	def createShader(gl: GL4, shaderType: Int, context: Class[_])(filename: String): ShaderCode = {
		ShaderCode.create(gl, shaderType, 1, context, Array(filename), false);
	}
	
	def createProgram(gl: GL4, shaders: ShaderCode*): ShaderProgram = {
		val retVal: ShaderProgram = new ShaderProgram();
		retVal.init(gl);
		
		for(shader <- shaders)
		{
			retVal.add(shader);
		}
		
		return retVal;
	}
}

class Demo1 extends GLEventListener
{
	var program: ShaderProgram = null;
	var vBuffer: Int = -1;
	
	override def init(drawable: GLAutoDrawable): Unit = {
		val gl: GL4 = drawable.getGL().getGL4();
		
		val createVertexShader = ShaderLoader.createShader(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass())_;
		val createFragmentShader = ShaderLoader.createShader(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass())_;
		
		try
		{
			val vShader: ShaderCode = createVertexShader("shaders/vshader.glsl");
			if(vShader.compile(gl, System.out) == false)
				throw new Exception("Failed to compile vertex shader");
			
			val fShader: ShaderCode = createFragmentShader("shaders/fshader.glsl");
			if(fShader.compile(gl, System.out) == false)
				throw new Exception("Failed to compile fragment shader");
			
			program = ShaderLoader.createProgram(gl, vShader, fShader);
			if(program.link(gl, System.out) == false)
				throw new Exception("Failed to link program");
			
			//No longer needed
			vShader.destroy(gl);
			fShader.destroy(gl);
			
			val vertexArrays: IntBuffer = IntBuffer.allocate(1);
			gl.glGenBuffers(1, vertexArrays);
			vBuffer = vertexArrays.get();
		}
		catch
		{
			case e: Exception => {
				e.printStackTrace();
				System.exit(1);
			}
		}
	}

	override def display(drawable: GLAutoDrawable): Unit = {
		val gl: GL4 = drawable.getGL().getGL4();

		val redArray: Array[Float] = Array(1.0f, 0.0f, 0.0f, 1.0f);
		gl.glClearBufferfv(GL2ES3.GL_COLOR, 0, redArray, 0);
		
		program.useProgram(gl, true);
		
		gl.glBindVertexArray(vBuffer);
		gl.glPointSize(20.0f);
		gl.glDrawArrays(GL.GL_POINTS, 0, 1);		
	}

	override def reshape(drawable: GLAutoDrawable, x: Int, y: Int, width: Int, height: Int): Unit = {
	}

	override def dispose(drawable: GLAutoDrawable): Unit = {
  		val gl: GL4 = drawable.getGL().getGL4();
  		
		if(program != null)
		{
			program.destroy(gl);
		}
	}
}

object EntryPoint {
	def main(args: Array[String]): Unit = {
		val frameMain: Frame = new Frame("Main Window");
		frameMain.setLayout(new BorderLayout());

		val animator: Animator = new Animator();
		frameMain.addWindowListener(new WindowAdapter() {
			override def windowClosing(e: WindowEvent) = {
				System.exit(0);
			}
		});

		val canvas: GLCanvas = new GLCanvas();
		animator.add(canvas);

		canvas.addGLEventListener(new Demo1());

		frameMain.setSize(600, 600);
		frameMain.setLocation(200, 200);
		frameMain.add(canvas, BorderLayout.CENTER);
		frameMain.validate();
		frameMain.setVisible(true);
		
		animator.start();
	}
}