Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package fr.guillaume.prive.viper.core.graphic; import org.lwjgl.LWJGLException; import org.lwjgl.opengl.ContextAttribs; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.DisplayMode; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.PixelFormat; import static fr.guillaume.prive.viper.core.commons.GameConstant.*; import fr.guillaume.prive.viper.core.model.Camera; import fr.guillaume.prive.viper.core.model.Vertex; import fr.guillaume.prive.viper.core.model.obj.ObjLoader; import fr.guillaume.prive.viper.core.model.obj.ObjModel; import fr.guillaume.prive.viper.core.model.texture.PNGTextureLoader; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.nio.FloatBuffer; import java.nio.IntBuffer; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30; import org.lwjgl.util.glu.GLU; import org.lwjgl.util.vector.Matrix4f; import org.lwjgl.util.vector.Vector3f; /** * * @author Guillaume BERTRAND */ public class GraphicMotor { private static GraphicMotor instance; private int shipShaderId = 0; private int shipVaoId = 0; private int shipVboId = 0; private int shipVboiId = 0; private int shipVboiLenght = 0; private int shipTextureId = 0; private boolean drawPolygonFrame = false; private int useTextureLocation = 0; private Camera camera = null; private int projectionMatrixLocation = 0; private int viewMatrixLocation = 0; private int modelMatrixLocation = 0; private Matrix4f modelMatrix = null; private FloatBuffer matrix44Buffer = null; public static void setup() { GraphicMotor.checkInstance(); GraphicMotor.setupOpenGL(); GraphicMotor.setupCamera(); GraphicMotor.setupMatrices(); GraphicMotor.setupTextures(); GraphicMotor.setupShaders(); GraphicMotor.setupObjModels(); } public static void compute() { GraphicMotor.checkInstance(); instance.camera.compute(); GL20.glUseProgram(instance.shipShaderId); instance.camera.getProjectionMatrix().store(instance.matrix44Buffer); instance.matrix44Buffer.flip(); GL20.glUniformMatrix4(instance.projectionMatrixLocation, false, instance.matrix44Buffer); instance.camera.getViewMatrix().store(instance.matrix44Buffer); instance.matrix44Buffer.flip(); GL20.glUniformMatrix4(instance.viewMatrixLocation, false, instance.matrix44Buffer); instance.modelMatrix.store(instance.matrix44Buffer); instance.matrix44Buffer.flip(); GL20.glUniformMatrix4(instance.modelMatrixLocation, false, instance.matrix44Buffer); GL20.glUseProgram(0); GraphicMotor.exitOnGLError("logicCycle"); } public static void draw() { GraphicMotor.checkInstance(); GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GL20.glUseProgram(instance.shipShaderId); GL20.glUniform1i(instance.useTextureLocation, instance.drawPolygonFrame ? 0 : 1); int drawStyle = instance.drawPolygonFrame ? GL11.GL_LINE_LOOP : GL11.GL_TRIANGLES; GL13.glActiveTexture(GL13.GL_TEXTURE0); GL11.glBindTexture(GL11.GL_TEXTURE_2D, instance.shipTextureId); GL30.glBindVertexArray(instance.shipVaoId); GL20.glEnableVertexAttribArray(0); GL20.glEnableVertexAttribArray(1); GL20.glEnableVertexAttribArray(2); GL20.glEnableVertexAttribArray(3); GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, instance.shipVboiId); GL11.glDrawElements(drawStyle, instance.shipVboiLenght, GL11.GL_UNSIGNED_INT, 0); GL20.glDisableVertexAttribArray(0); GL20.glDisableVertexAttribArray(1); GL20.glDisableVertexAttribArray(2); GL20.glDisableVertexAttribArray(3); GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0); GL30.glBindVertexArray(0); GL20.glUseProgram(0); } public static void destroy() { GraphicMotor.checkInstance(); } public static void addCameraMovement(float movement) { GraphicMotor.checkInstance(); instance.camera.addMovement(movement); } public static void addCameraRotation(float deltaX, float deltaY) { GraphicMotor.checkInstance(); instance.camera.addRotation(deltaX, deltaY); } public static void switchDrawPolygonFrame() { GraphicMotor.checkInstance(); instance.drawPolygonFrame = !instance.drawPolygonFrame; } private static void setupOpenGL() { try { PixelFormat pixelFormat = new PixelFormat(); ContextAttribs contextAtrributes = new ContextAttribs(3, 2).withForwardCompatible(true) .withProfileCore(true); Display.setDisplayMode(new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT)); Display.setTitle(WINDOW_NAME); Display.create(pixelFormat, contextAtrributes); } catch (LWJGLException e) { throw new IllegalStateException("OpenGL init error", e); } GL11.glClearColor(0f, 0f, 0f, 0f); GL11.glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); GL11.glEnable(GL11.GL_DEPTH_TEST); GL11.glEnable(GL11.GL_BLEND); } private static void setupCamera() { instance.camera = new Camera(); } private static void setupMatrices() { instance.modelMatrix = new Matrix4f(); Vector3f modelScale = new Vector3f(1.0f / SCALE, 1.0f / SCALE, 1.0f / SCALE); Matrix4f.scale(modelScale, instance.modelMatrix, instance.modelMatrix); instance.matrix44Buffer = BufferUtils.createFloatBuffer(16); } private static void setupTextures() { instance.shipTextureId = PNGTextureLoader.loadTexture("resources/model/fighter.png", GL13.GL_TEXTURE0); } private static void setupShaders() { int vsId = GraphicMotor.loadShader("resources/shader/ship.vert", GL20.GL_VERTEX_SHADER); int fsId = GraphicMotor.loadShader("resources/shader/ship.frag", GL20.GL_FRAGMENT_SHADER); instance.shipShaderId = GL20.glCreateProgram(); GL20.glAttachShader(instance.shipShaderId, vsId); GL20.glAttachShader(instance.shipShaderId, fsId); GL20.glBindAttribLocation(instance.shipShaderId, 0, "in_Position"); GL20.glBindAttribLocation(instance.shipShaderId, 1, "Normal"); GL20.glBindAttribLocation(instance.shipShaderId, 2, "in_Color"); GL20.glBindAttribLocation(instance.shipShaderId, 3, "in_TextureCoord"); GL20.glLinkProgram(instance.shipShaderId); GL20.glValidateProgram(instance.shipShaderId); instance.projectionMatrixLocation = GL20.glGetUniformLocation(instance.shipShaderId, "projectionMatrix"); instance.viewMatrixLocation = GL20.glGetUniformLocation(instance.shipShaderId, "viewMatrix"); instance.modelMatrixLocation = GL20.glGetUniformLocation(instance.shipShaderId, "modelMatrix"); instance.useTextureLocation = GL20.glGetUniformLocation(instance.shipShaderId, "use_texture"); GraphicMotor.exitOnGLError("setupShaders"); } private static void setupObjModels() { ObjModel spaceShipModel = ObjLoader.loadModel(new File("resources/model/fighter.obj")); FloatBuffer verticesBuffer = BufferUtils .createFloatBuffer(Vertex.ELEMENT_COUNT * spaceShipModel.getVertices().size()); spaceShipModel.getVertices().stream().forEach((v) -> verticesBuffer.put(v.getElements())); verticesBuffer.flip(); instance.shipVaoId = GL30.glGenVertexArrays(); GL30.glBindVertexArray(instance.shipVaoId); instance.shipVboId = GL15.glGenBuffers(); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, instance.shipVboId); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, verticesBuffer, GL15.GL_STATIC_DRAW); GL20.glVertexAttribPointer(0, Vertex.POSITION_ELEMENT_COUNT, GL11.GL_FLOAT, false, Vertex.STRIDE, 0); GL20.glVertexAttribPointer(1, Vertex.NORMAL_ELEMENT_COUNT, GL11.GL_FLOAT, false, Vertex.STRIDE, Vertex.NORMAL_BYTE_OFFSET); GL20.glVertexAttribPointer(2, Vertex.COLOR_ELEMENT_COUNT, GL11.GL_FLOAT, false, Vertex.STRIDE, Vertex.COLOR_BYTE_OFFSET); GL20.glVertexAttribPointer(3, Vertex.TEXTURE_ELEMENT_COUNT, GL11.GL_FLOAT, false, Vertex.STRIDE, Vertex.TEXTURE_BYTE_OFFSET); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0); GL30.glBindVertexArray(0); instance.shipVboiLenght = spaceShipModel.getIndices().length; IntBuffer indicesBuffer = BufferUtils.createIntBuffer(instance.shipVboiLenght); indicesBuffer.put(spaceShipModel.getIndices()); indicesBuffer.flip(); instance.shipVboiId = GL15.glGenBuffers(); GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, instance.shipVboiId); GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL15.GL_STATIC_DRAW); GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0); } private static int loadShader(String filename, int type) { StringBuilder shaderSource = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new FileReader(filename))) { String line; while ((line = reader.readLine()) != null) { shaderSource.append(line).append("\n"); } } catch (IOException e) { throw new IllegalStateException("Shader file i/o error", e); } int shaderID = GL20.glCreateShader(type); GL20.glShaderSource(shaderID, shaderSource); GL20.glCompileShader(shaderID); return shaderID; } public static void exitOnGLError(String errorMessage) { int errorValue = GL11.glGetError(); if (errorValue != GL11.GL_NO_ERROR) { String errorString = GLU.gluErrorString(errorValue); System.err.println("ERROR - " + errorMessage + ": " + errorString); if (Display.isCreated()) Display.destroy(); { System.exit(-1); } } } private static void checkInstance() { if (instance == null) { instance = new GraphicMotor(); } } private GraphicMotor() { super(); } }