Java tutorial
/* * 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(); } }