fr.guillaume.prive.viper.core.graphic.GraphicMotor.java Source code

Java tutorial

Introduction

Here is the source code for fr.guillaume.prive.viper.core.graphic.GraphicMotor.java

Source

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