com.drazisil.opengl3demo.OpenGL3Demo.java Source code

Java tutorial

Introduction

Here is the source code for com.drazisil.opengl3demo.OpenGL3Demo.java

Source

/*
 * Copyright 2015 Joseph W Becher <jwbecher@drazisil.com>
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.drazisil.opengl3demo;

import org.lwjgl.BufferUtils;
import org.lwjgl.Sys;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWKeyCallback;
import org.lwjgl.glfw.GLFWvidmode;
import org.lwjgl.opengl.*;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;

import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.System.exit;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.glGenBuffers;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;

public class OpenGL3Demo {

    // GLFW error and key callbacks
    private final ThreadLocal<GLFWErrorCallback> errorCallback = new ThreadLocal<GLFWErrorCallback>();
    private final ThreadLocal<GLFWKeyCallback> keyCallback = new ThreadLocal<GLFWKeyCallback>();

    //private static Renderer renderer;

    // window context
    private long window;

    // windows width, height and title
    private final int WIDTH = 1152;
    private final int HEIGHT = 720;
    private CharSequence title = "OpenGL 4 Demo";

    // is game running
    private boolean isRunning = false;
    private double currentTime;
    private int vertexArrays;
    private int shaderProgram;
    private int colorBufferObject;
    //private float delta;
    //private long lastFrame;

    public void run() {
        init();

        // run the main loop
        loop();

        // cleanup
        cleanup();

    }

    private void init() {

        initOpenGl();

        initShaders();

    }

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

        // create and set the glfw error callback
        setupErrorCallback();

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

        // create the window
        window = glfwCreateWindow(WIDTH, HEIGHT, title, 0, 0);

        // Check if window was created
        if (window == 0) {
            glfwTerminate();
            exit(-1);
        }

        // 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);

        // Created and set the glfw key callback
        setupKeyCallback();

        // make context current
        glfwMakeContextCurrent(window);

        // It is required to have an active OpenGL context
        GLContext.createFromCurrent();

        System.out.println("OpenGL Version " + GL11.glGetString(GL11.GL_VERSION));

        vertexArrays = glGenVertexArrays();
        glBindVertexArray(vertexArrays);

        colorBufferObject = glGenBuffers();
    }

    private void initShaders() {
        int vertShader = 0;
        int tessShader1 = 0;
        int tessShader2 = 0;
        int geoShader = 0;
        int fragShader = 0;

        try {
            vertShader = createShader("resources/shaders/openGlDemo.vert.glsl",
                    ARBVertexShader.GL_VERTEX_SHADER_ARB);
            /*
                        tessShader1 = createShader("resources/shaders/openGlDemo.tess-control.glsl", ARBTessellationShader.GL_TESS_CONTROL_SHADER);
                        tessShader2 = createShader("resources/shaders/openGlDemo.tess-eval.glsl", ARBTessellationShader.GL_TESS_EVALUATION_SHADER);
                        geoShader = createShader("resources/shaders/openGlDemo.geo.glsl", ARBGeometryShader4.GL_GEOMETRY_SHADER_ARB);
            */
            fragShader = createShader("resources/shaders/openGlDemo.frag.glsl",
                    ARBFragmentShader.GL_FRAGMENT_SHADER_ARB);
        } catch (Exception exc) {
            exc.printStackTrace();
            return;
        } finally {
            if (vertShader == 0 || fragShader == 0) {
                return;
            }
        }

        // Create shaderProgram, attach shaders to it, and link it
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram, vertShader);
        /*
                glAttachShader(shaderProgram, tessShader1);
                glAttachShader(shaderProgram, tessShader2);
                glAttachShader(shaderProgram, geoShader);
        */
        glAttachShader(shaderProgram, fragShader);
        glLinkProgram(shaderProgram);

        // Delete the shaders as the shaderProgram has them now
        glDeleteShader(vertShader);
        /*
                glDeleteShader(tessShader1);
                glDeleteShader(tessShader2);
                glDeleteShader(geoShader);
        */
        glDeleteShader(fragShader);

    }

    private void loop() {
        // It is required to have an active OpenGL context
        GLContext.createFromCurrent();

        currentTime = glfwGetTime();

        // Set the game as running
        isRunning = true;

        while (isRunning) {
            if (glfwWindowShouldClose(window) == 1) {
                isRunning = false;
            }

            // check for key events
            glfwPollEvents();

            currentTime = glfwGetTime();

            render();

            // swap the buffers
            glfwSwapBuffers(window);
        }
    }

    private void render() {
        float colors[] = { (float) sin(currentTime) * 0.5f + 0.5f, (float) cos(currentTime) * 0.5f + 0.5f, 0.0f,
                1.0f };

        FloatBuffer vertexColorsFloat = BufferUtils.createFloatBuffer(colors.length);
        vertexColorsFloat.put(colors);
        vertexColorsFloat.flip();

        glClearBuffer(GL_COLOR, 0, vertexColorsFloat);

        glClearColor(0.0f, 0.2f, 0.0f, 1.0f);
        glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

        // Use the shaderProgram object we created earlier for rendering
        glUseProgram(shaderProgram);

        float[] offsetFloat = new float[] { (float) sin(currentTime) * 0.5f, (float) cos(currentTime) * 0.6f, 0.0f,
                0.0f };

        FloatBuffer vertexOffsetFloat = BufferUtils.createFloatBuffer(offsetFloat.length);
        vertexOffsetFloat.put(offsetFloat);
        vertexOffsetFloat.flip();

        glVertexAttrib4(0, vertexOffsetFloat);
        glVertexAttrib4(1, vertexColorsFloat);

        //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

        // Draw one triangle
        glDrawArrays(GL_TRIANGLES, 0, 3);

    }

    private void cleanup() {
        glDeleteVertexArrays(vertexArrays);
        glDeleteProgram(shaderProgram);
        glDeleteVertexArrays(vertexArrays);

        // destroy window
        glfwDestroyWindow(window);

        // terminate GLFW
        glfwTerminate();

    }

    private void setupKeyCallback() {
        keyCallback.set(new GLFWKeyCallback() {
            @Override
            public void invoke(long window, int key, int scancode, int action, int mods) {
                if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
                    isRunning = false;
                /*
                                if (key == GLFW_KEY_A && (action == GLFW_PRESS || action == GLFW_REPEAT))
                renderer.computeXYOffset(delta, "Left");
                                if (key == GLFW_KEY_D && (action == GLFW_PRESS || action == GLFW_REPEAT))
                renderer.computeXYOffset(delta, "Right");
                                if (key == GLFW_KEY_W && (action == GLFW_PRESS || action == GLFW_REPEAT))
                renderer.computeXYOffset(delta, "Up");
                                if (key == GLFW_KEY_S && (action == GLFW_PRESS || action == GLFW_REPEAT))
                renderer.computeXYOffset(delta, "Down");
                                if (key == GLFW_KEY_KP_0 && action == GLFW_PRESS)
                renderer.computeXYOffset(delta, "Reset");
                    
                                if (key == GLFW_KEY_LEFT && (action == GLFW_PRESS || action == GLFW_REPEAT))
                renderer.computeRotation(delta, "CW");
                                if (key == GLFW_KEY_RIGHT && (action == GLFW_PRESS || action == GLFW_REPEAT))
                renderer.computeRotation(delta, "CCW");
                */

            }
        });

        // Set key keyCallback
        glfwSetKeyCallback(window, keyCallback.get());

    }

    private void setupErrorCallback() {
        // Set error keyCallback
        errorCallback.set(new GLFWErrorCallback() {
            @Override
            public void invoke(int error, long description) {
                System.err.println(description);
            }
        });

        // Set error keyCallback
        glfwSetErrorCallback(errorCallback.get());
    }

    /*
    * With the exception of syntax, setting up vertex and fragment shaders
    * is the same.
    * @param the name and path to the vertex shader
    */
    private int createShader(String filename, int shaderType) throws Exception {
        int shader = 0;
        try {
            shader = ARBShaderObjects.glCreateShaderObjectARB(shaderType);

            if (shader == 0)
                return 0;

            ARBShaderObjects.glShaderSourceARB(shader, readFileAsString(filename));
            ARBShaderObjects.glCompileShaderARB(shader);

            if (ARBShaderObjects.glGetObjectParameteriARB(shader,
                    ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB) == GL11.GL_FALSE)
                throw new RuntimeException("Error creating shader: " + getLogInfo(shader));

            return shader;
        } catch (Exception exc) {
            ARBShaderObjects.glDeleteObjectARB(shader);
            throw exc;
        }
    }

    private static String getLogInfo(int obj) {
        return ARBShaderObjects.glGetInfoLogARB(obj,
                ARBShaderObjects.glGetObjectParameteriARB(obj, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB));
    }

    private String readFileAsString(String filename) throws Exception {
        StringBuilder source = new StringBuilder();

        FileInputStream in = new FileInputStream(filename);

        Exception exception = null;

        BufferedReader reader;
        try {
            reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));

            Exception innerExc = null;
            try {
                String line;
                while ((line = reader.readLine()) != null)
                    source.append(line).append('\n');
            } catch (Exception exc) {
                exception = exc;
            } finally {
                try {
                    reader.close();
                } catch (Exception exc) {
                    if (innerExc == null)
                        innerExc = exc;
                    else
                        exc.printStackTrace();
                }
            }

            if (innerExc != null)
                throw innerExc;
        } catch (Exception exc) {
            exception = exc;
        } finally {
            try {
                in.close();
            } catch (Exception exc) {
                if (exception == null)
                    exception = exc;
                else
                    exc.printStackTrace();
            }

            if (exception != null) {
                throw exception;
            }
        }

        return source.toString();
    }

    public static void main(String[] argv) {
        //System.setProperty("org.lwjgl.librarypath", new File("natives/windows/x86").getAbsolutePath());
        //renderer = new Renderer();
        OpenGL3Demo openGL3Demo = new OpenGL3Demo();
        openGL3Demo.run();
    }

}