package morphy.app;

import org.apache.commons.io.IOUtils;
import org.lwjgl.Sys;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;

import java.io.StringWriter;
import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;

import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.BufferUtils.*;
import static org.lwjgl.system.MemoryUtil.*;

public class Plant3DMain {

    // We need to strongly reference callback instances.
    private GLFWErrorCallback errorCallback;
    private GLFWKeyCallback   keyCallback;

    // The window handle
    private long window;

    private String source(String path) {
        StringWriter writer = new StringWriter();
        try {
            IOUtils.copy(this.getClass().getResourceAsStream(path), writer, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return writer.toString();
    }

    public void run() {
        System.out.println("Hello LWJGL " + Sys.getVersion() + "!");

        try {
            init();
            loop();

            // Release window and window callbacks
            glfwDestroyWindow(window);
            keyCallback.release();
        } finally {
            // Terminate GLFW and release the GLFWerrorfun
            glfwTerminate();
            errorCallback.release();
        }
    }

    private void init() {

        // Setup an error callback. The default implementation
        // will print the error message in System.err.
        glfwSetErrorCallback(errorCallback = errorCallbackPrint(System.err));

        // Initialize GLFW. Most GLFW functions will not work before doing this.
        if ( glfwInit() != GL11.GL_TRUE )
            throw new IllegalStateException("Unable to initialize GLFW");

        // Configure our window
        glfwDefaultWindowHints(); // optional, the current window hints are already the default
        glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // the window will stay hidden after creation
        glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // the window will be resizable
        int WIDTH = 300;
        int HEIGHT = 300;

        // Create the window
        window = glfwCreateWindow(WIDTH, HEIGHT, "Hello World!", NULL, NULL);
        if ( window == NULL )
            throw new RuntimeException("Failed to create the GLFW window");

        // Setup a key callback. It will be called every time a key is pressed, repeated or released.
        glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
            @Override
            public void invoke(long window, int key, int scancode, int action, int mods) {
                if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
                    glfwSetWindowShouldClose(window, GL_TRUE); // We will detect this in our rendering loop
            }
        });

        // Get the resolution of the primary monitor
        ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
        // Center our window
        glfwSetWindowPos(
                window,
                (GLFWvidmode.width(vidmode) - WIDTH) / 2,
                (GLFWvidmode.height(vidmode) - HEIGHT) / 2
        );

        // Make the OpenGL context current
        glfwMakeContextCurrent(window);
        // Enable v-sync
        glfwSwapInterval(1);

        // Make the window visible
        glfwShowWindow(window);
    }

    private void loop() {
        // This line is critical for LWJGL's interoperation with GLFW's
        // OpenGL context, or any context that is managed externally.
        // LWJGL detects the context that is current in the current thread,
        // creates the ContextCapabilities instance and makes the OpenGL
        // bindings available for use.
        GLContext.createFromCurrent();

        // Set the clear color
        glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

        int progId = glCreateProgram();
        int vShader = glCreateShader(GL_VERTEX_SHADER);
        int fShader = glCreateShader(GL_FRAGMENT_SHADER);

        glShaderSource(vShader, source("SimpleVertexShader.glsl"));
        glShaderSource(fShader, source("SimpleFragmentShader.glsl"));

        glCompileShader(vShader);
        glCompileShader(fShader);
        glAttachShader(progId, vShader);
        glAttachShader(progId, fShader);
        glLinkProgram(progId);

        System.out.println(glGetShaderInfoLog(vShader));
        System.out.println(glGetShaderInfoLog(fShader));

        glDeleteShader(vShader);
        glDeleteShader(fShader);

        DoubleBuffer vertexes = createDoubleBuffer(9);
        vertexes.put(new double[]{
                -1, -1, 1,
                1, -1, 1,
                0, 1, 1,
        });
        vertexes.flip();
        glVertex3dv(vertexes);

        // Run the rendering loop until the user has attempted to close
        // the window or has pressed the ESCAPE key.
        while (glfwWindowShouldClose(window) == GL_FALSE) {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer

            glUseProgram(progId);

            glEnableVertexAttribArray(0);
            glVertexAttribPointer(
                    3,                  // size
                    GL_DOUBLE,          // type
                    false,              // normalized?
                    0,                  // stride
                    vertexes            // buffer
            );
            glDrawArrays(GL_TRIANGLES, 0, 3);
            glDisableVertexAttribArray(0);

            glfwSwapBuffers(window); // swap the color buffers

            // Poll for window events. The key callback above will only be
            // invoked during this call.
            glfwPollEvents();
        }
    }

    public static void main(String[] args) {
        SharedLibraryLoader.load();
        new Plant3DMain().run();
    }

}

@@ -329,24 +329,63 @@
 ngl.GL11.*;%0A
+import static org.lwjgl.opengl.GL15.*;%0A
 import stati
@@ -4832,24 +4832,25 @@
 flip();%0A
+%0A
         
 glVertex
@@ -4845,28 +4845,401 @@
     
-glVertex3dv(vertexes
+int vaoId = glGenBuffers();%0A        glBindBuffer(GL_VERTEX_ARRAY_BUFFER_BINDING, vaoId);%0A        int vboId = glGenBuffers();%0A        glBindBuffer(GL_ARRAY_BUFFER, vboId);%0A        glBufferData(GL_ARRAY_BUFFER, vertexes, GL_STATIC_DRAW);%0A        glVertexAttribPointer(0, 3, GL_DOUBLE, false, 0, 0);%0A        glBindBuffer(GL_ARRAY_BUFFER, 0);%0A        glBindBuffer(GL_VERTEX_ARRAY_BUFFER_BINDING, 0
 );%0A%0A
@@ -5566,33 +5566,56 @@
   gl
-EnableVertexAttribArray(0
+BindBuffer(GL_VERTEX_ARRAY_BUFFER_BINDING, vaoId
 );%0A 
@@ -5619,32 +5619,38 @@
 ;%0A            gl
+Enable
 VertexAttribPoin
@@ -5649,280 +5649,15 @@
 trib
-Pointer(%0A                    3,                  // size%0A                    GL_DOUBLE,          // type%0A                    false,              // normalized?%0A                    0,                  // stride%0A                    vertexes            // buffer%0A            
+Array(0
 );%0A 
@@ -5743,16 +5743,77 @@
 rray(0);
+%0A            glBindBuffer(GL_VERTEX_ARRAY_BUFFER_BINDING, 0);
 %0A%0A      

the first runnable 3d example: triangle