com.grillecube.engine.opengl.GLFWWindow.java Source code

Java tutorial

Introduction

Here is the source code for com.grillecube.engine.opengl.GLFWWindow.java

Source

/**
**   This file is part of the project https://github.com/toss-dev/VoxelEngine
**
**   License is available here: https://raw.githubusercontent.com/toss-dev/VoxelEngine/master/LICENSE.md
**
**   PEREIRA Romain
**                                       4-----7          
**                                      /|    /|
**                                     0-----3 |
**                                     | 5___|_6
**                                     |/    | /
**                                     1-----2
*/

package com.grillecube.engine.opengl;

import java.nio.DoubleBuffer;
import java.util.ArrayList;

import org.lwjgl.BufferUtils;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWCursorPosCallback;
import org.lwjgl.glfw.GLFWKeyCallback;
import org.lwjgl.glfw.GLFWMouseButtonCallback;
import org.lwjgl.glfw.GLFWScrollCallback;
import org.lwjgl.glfw.GLFWWindowFocusCallback;
import org.lwjgl.glfw.GLFWWindowSizeCallback;
import org.lwjgl.opengl.GL11;

import com.grillecube.engine.opengl.object.GLObject;

/**
 * 
 * HOW TO USE:
 * 
 * create a new instance (GLFWWindow window = new GLFWWindow())
 * 
 * call 'window.create()' to set GLContext + resize and error callback
 * 
 * window.prepareScreen(); //clear screen ... // rendering stuff goes here
 * window.flushScreen(); //swap buffer + update fps counter
 */
public class GLFWWindow implements GLFWListenerKeyPress, GLObject {
    public static final int OS_LINUX = 0;
    public static final int OS_WINDOWS = 1;
    public static final int OS_MAC = 2;

    public static final String OS_NAME = System.getProperty("os.name");
    private static final String _OS_NAME = OS_NAME.toLowerCase();
    public static final int OS = _OS_NAME.contains("win") ? OS_WINDOWS
            : _OS_NAME.contains("mac") ? OS_MAC : OS_LINUX;

    /** screen resolution */
    private int _screenx;
    private int _screeny;

    /** window pointer */
    private long _ptr;

    /** window size (in pixels) */
    private int _width;
    private int _height;

    /** window size (in pixels) */
    private DoubleBuffer _bufferX;
    private DoubleBuffer _bufferY;

    private double _mouseX;
    private double _mouseY;
    private double _prev_mouseX;
    private double _prev_mouseY;

    /** frames data */
    private long _prev_frame; // previous frame timer
    private long _frames; // total frames flushed
    private int _fps_counter; // frame per second counter
    private int _fps; // last frame per second calculated

    /** events handler */
    private ArrayList<GLFWListenerResize> _listeners_resize;
    private ArrayList<GLFWListenerKeyPress> _listeners_key_press;
    private ArrayList<GLFWListenerKeyRelease> _listeners_key_release;
    private ArrayList<GLFWListenerCursorPos> _listeners_cursor_pos;
    private ArrayList<GLFWListenerMouseScroll> _listeners_mouse_scroll;
    private ArrayList<GLFWListenerMousePress> _listeners_mouse_press;
    private ArrayList<GLFWListenerMouseRelease> _listeners_mouse_release;
    private ArrayList<GLFWListenerMouseEnter> _listeners_mouse_enter;
    private ArrayList<GLFWListenerMouseExit> _listeners_mouse_exit;

    /** events callback for garbage collector */
    private GLFWScrollCallback _callback_scroll;
    private GLFWCursorPosCallback _callback_cursor_pos;
    private GLFWMouseButtonCallback _callback_mouse_button;
    private GLFWKeyCallback _callback_key;
    private GLFWWindowSizeCallback _resize_callback;
    private GLFWWindowFocusCallback _focus_callback;

    private boolean _mouse_is_in;

    private boolean _focus;

    public GLFWWindow() {
    }

    /** create the window and initialize gl context */

    public void create(int width, int height, String title) {

        if (width == 0) {
            width = 1;
        }

        if (height == 0) {
            height = 1;
        }

        if (GLFWWindow.OS == GLFWWindow.OS_LINUX || GLFWWindow.OS == GLFWWindow.OS_MAC) {
            GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
            GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 3);
            GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
        }

        this._ptr = GLFW.glfwCreateWindow(width, height, title, 0, 0);
        if (this._ptr == 0) {
            System.err.println("Couldnt create glfw window");
            return;
        }

        this._width = width;
        this._height = height;

        this._mouseX = width / 2;
        this._mouseY = height / 2;

        this._prev_mouseX = width / 2;
        this._prev_mouseY = height / 2;

        this._bufferX = BufferUtils.createDoubleBuffer(1);
        this._bufferY = BufferUtils.createDoubleBuffer(1);
        this._screenx = (int) this._bufferX.get();
        this._screeny = (int) this._bufferY.get();
        this._bufferX.clear();
        this._bufferY.clear();

        this._prev_frame = System.currentTimeMillis();
        this._frames = 0;
        this._fps_counter = 0;
        this._fps = 0;

        this.initEvents();
    }

    /** return screen resolution (width) */
    public int getScreenWidth() {
        return (this._screenx);
    }

    /** return screen resolution (height) */
    public int getScreenHeight() {
        return (this._screeny);
    }

    private void initEvents() {
        this._listeners_resize = new ArrayList<GLFWListenerResize>();
        this._listeners_key_press = new ArrayList<GLFWListenerKeyPress>();
        this._listeners_key_release = new ArrayList<GLFWListenerKeyRelease>();
        this._listeners_cursor_pos = new ArrayList<GLFWListenerCursorPos>();
        this._listeners_mouse_scroll = new ArrayList<GLFWListenerMouseScroll>();
        this._listeners_mouse_press = new ArrayList<GLFWListenerMousePress>();
        this._listeners_mouse_release = new ArrayList<GLFWListenerMouseRelease>();
        this._listeners_mouse_enter = new ArrayList<GLFWListenerMouseEnter>();
        this._listeners_mouse_exit = new ArrayList<GLFWListenerMouseExit>();

        this.initWindowEvents();
        this.initKeyEvents();
        this.initMouseEvents();

        this.addKeyPressListener(this);
    }

    private void initWindowEvents() {
        this._resize_callback = new GLFWWindowSizeCallback() {
            @Override
            public void invoke(long window, int width, int height) {
                resize(width, height);
                GLFWWindow.this.invokeWindowResize(width, height);
            }
        };
        GLFW.glfwSetWindowSizeCallback(this._ptr, this._resize_callback);

        this._focus_callback = new GLFWWindowFocusCallback() {
            @Override
            public void invoke(long window, boolean focused) {
                _focus = focused;
            }
        };
        GLFW.glfwSetWindowFocusCallback(this._ptr, this._focus_callback);

    }

    /** window resizement */
    private void invokeWindowResize(int width, int height) {
        for (GLFWListenerResize listener : this._listeners_resize) {
            listener.invokeResize(this, width, height);
        }
    }

    /** keyboard key press */
    private void invokeKeyPressListeners(int key, int scancode, int mods) {
        for (GLFWListenerKeyPress listener : this._listeners_key_press) {
            listener.invokeKeyPress(this, key, scancode, mods);
        }
    }

    /** keyboard key release */
    private void invokeKeyReleaseListeners(int key, int scancode, int mods) {
        for (GLFWListenerKeyRelease listener : this._listeners_key_release) {
            listener.invokeKeyRelease(this, key, scancode, mods);
        }
    }

    /** mouse move */
    private void invokeCursorPosListeners(double posx, double posy) {
        for (GLFWListenerCursorPos listener : this._listeners_cursor_pos) {
            listener.invokeCursorPos(this, posx, posy);
        }
    }

    /** mouse move */
    private void invokeScrollListeners(double posx, double posy) {
        for (GLFWListenerMouseScroll listener : this._listeners_mouse_scroll) {
            listener.invokeMouseScroll(this, posx, posy);
        }
    }

    /** mouse release */
    private void invokeMouseReleaseListeners(int button, int mods) {
        for (GLFWListenerMouseRelease listener : this._listeners_mouse_release) {
            listener.invokeMouseRelease(this, button, mods);
        }
    }

    /** mouse press */
    private void invokeMousePressListeners(int button, int mods) {
        for (GLFWListenerMousePress listener : this._listeners_mouse_press) {
            listener.invokeMousePress(this, button, mods);
        }
    }

    /** add listeners */
    public void addResizeListener(GLFWListenerResize listener) {
        this._listeners_resize.add(listener);
    }

    public void addKeyPressListener(GLFWListenerKeyPress listener) {
        this._listeners_key_press.add(listener);
    }

    public void addKeyReleaseListener(GLFWListenerKeyRelease listener) {
        this._listeners_key_release.add(listener);
    }

    public void addMousePressListener(GLFWListenerMousePress listener) {
        this._listeners_mouse_press.add(listener);
    }

    public void addMouseReleaseListener(GLFWListenerMouseRelease listener) {
        this._listeners_mouse_release.add(listener);
    }

    public void addCursorPosListener(GLFWListenerCursorPos listener) {
        this._listeners_cursor_pos.add(listener);
    }

    public void addMouseScrollListener(GLFWListenerMouseScroll listener) {
        this._listeners_mouse_scroll.add(listener);
    }

    public void addMouseEnterListener(GLFWListenerMouseEnter listener) {
        this._listeners_mouse_enter.add(listener);
    }

    public void addMouseExitListener(GLFWListenerMouseExit listener) {
        this._listeners_mouse_exit.add(listener);
    }

    public void removeResizeListener(GLFWListenerResize listener) {
        this._listeners_resize.remove(listener);
    }

    public void removeKeyPressListener(GLFWListenerKeyPress listener) {
        this._listeners_key_press.remove(listener);
    }

    public void removeKeyReleaseListener(GLFWListenerKeyRelease listener) {
        this._listeners_key_release.remove(listener);
    }

    public void removeMousePressListener(GLFWListenerMousePress listener) {
        this._listeners_mouse_press.remove(listener);
    }

    public void removeMouseReleaseListener(GLFWListenerMouseRelease listener) {
        this._listeners_mouse_release.remove(listener);
    }

    public void removeCursorPosListener(GLFWListenerCursorPos listener) {
        this._listeners_cursor_pos.remove(listener);
    }

    public void removeMouseScrollListener(GLFWListenerMouseScroll listener) {
        this._listeners_mouse_scroll.remove(listener);
    }

    public void removeMouseEnterListener(GLFWListenerMouseEnter listener) {
        this._listeners_mouse_enter.remove(listener);
    }

    public void removeMouseExitListener(GLFWListenerMouseExit listener) {
        this._listeners_mouse_exit.remove(listener);
    }

    private void initKeyEvents() {
        this._callback_key = new GLFWKeyCallback() {
            @Override
            public void invoke(long window, int key, int scancode, int action, int mods) {
                if (action == GLFW.GLFW_PRESS) {
                    GLFWWindow.this.invokeKeyPressListeners(key, scancode, mods);
                } else if (action == GLFW.GLFW_RELEASE) {
                    GLFWWindow.this.invokeKeyReleaseListeners(key, scancode, mods);
                }
            }
        };
        GLFW.glfwSetKeyCallback(this._ptr, this._callback_key);
    }

    private void initMouseEvents() {
        this._callback_scroll = new GLFWScrollCallback() {

            @Override
            public void invoke(long window, double xpos, double ypos) {
                GLFWWindow.this.invokeScrollListeners(xpos, ypos);
            }
        };

        this._callback_cursor_pos = new GLFWCursorPosCallback() {

            @Override
            public void invoke(long window, double xpos, double ypos) {
                GLFWWindow.this.invokeCursorPosListeners(xpos, ypos);
            }
        };

        this._callback_mouse_button = new GLFWMouseButtonCallback() {

            @Override
            public void invoke(long window, int button, int action, int mods) {
                if (action == GLFW.GLFW_PRESS) {
                    GLFWWindow.this.invokeMousePressListeners(button, mods);
                } else {
                    GLFWWindow.this.invokeMouseReleaseListeners(button, mods);
                }
            }
        };
        GLFW.glfwSetScrollCallback(this._ptr, this._callback_scroll);
        GLFW.glfwSetCursorPosCallback(this._ptr, this._callback_cursor_pos);
        GLFW.glfwSetMouseButtonCallback(this._ptr, this._callback_mouse_button);
    }

    /** in pixels */
    public void setScreenPosition(int px, int py) {
        GLFW.glfwSetWindowPos(this.getPointer(), px, py);
    }

    /** enable or disable cursor */
    public void setCursor(boolean enable) {
        int value = (enable) ? GLFW.GLFW_CURSOR_NORMAL : GLFW.GLFW_CURSOR_DISABLED;
        GLFW.glfwSetInputMode(this._ptr, GLFW.GLFW_CURSOR, value);
    }

    public boolean isCursorEnabled() {
        return (GLFW.glfwGetInputMode(this._ptr, GLFW.GLFW_CURSOR) != GLFW.GLFW_CURSOR_DISABLED);
    }

    /** center the mouse on the screen */
    public void setCursorCenter() {
        this.setCursorPos(this._width / 2, this._height / 2);
    }

    /** set cursor position */
    public void setCursorPos(double x, double y) {
        GLFW.glfwSetCursorPos(this._ptr, x, y);
    }

    /** set window title */
    public void setTitle(String title) {
        GLFW.glfwSetWindowTitle(this._ptr, title);
    }

    /** enable or disable vsync (0 == disable, 1 == enable) */
    public void swapInterval(int v) {
        GLFW.glfwSwapInterval(v);
    }

    /** stop the window */
    @Override
    public void delete() {
        GLFW.glfwDestroyWindow(this._ptr);
    }

    public float getAspectRatio() {
        return (this._width / (float) this._height);
    }

    public void resize(int width, int height) {
        GL11.glViewport(0, 0, width, height);
        this._width = width;
        this._height = height;
    }

    public int getWidth() {
        return (this._width);
    }

    public int getHeight() {
        return (this._height);
    }

    public void setClearColor(float r, float g, float b, float a) {
        GL11.glClearColor(r, g, b, a);
    }

    /** should be call before rendering */
    public void clearScreen() {
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
    }

    public void update() {
        GLFW.glfwGetCursorPos(this._ptr, this._bufferX, this._bufferY);
        this._mouseX = this._bufferX.get();
        this._mouseY = this._bufferY.get();
        this._bufferX.clear();
        this._bufferY.clear();

        if (this._mouseX < 0 || this._mouseX >= this._width || this._mouseY < 0 || this._mouseY >= this._height) {
            if (this._mouse_is_in) {
                this.onMouseExit();
            }
            this._mouse_is_in = false;
        } else {
            if (!this._mouse_is_in) {
                this.onMouseEntered();
            }
            this._mouse_is_in = true;
        }
    }

    public void onMouseEntered() {
        for (GLFWListenerMouseEnter listener : this._listeners_mouse_enter) {
            listener.invokeMouseEnter(this, this.isCursorEnabled(), this._mouseX, this._mouseY);
        }
    }

    public void onMouseExit() {
        for (GLFWListenerMouseExit listener : this._listeners_mouse_exit) {
            listener.invokeMouseExit(this, this.isCursorEnabled(), this._mouseX, this._mouseY);
        }
    }

    /** should be call after rendering */
    public void flushScreen() {
        GLFW.glfwSwapBuffers(this._ptr);
        GLFW.glfwPollEvents();

        this._prev_mouseX = this._mouseX;
        this._prev_mouseY = this._mouseY;

        this.updateFpsCounter();

        GLH.glhCheckError("GLFWWindow.flushScreen()");
    }

    private void updateFpsCounter() {
        if (System.currentTimeMillis() - this._prev_frame >= 1000) {
            this._fps = this._fps_counter;
            this._fps_counter = 0;
            this._prev_frame = System.currentTimeMillis();
        } else {
            this._fps_counter++;
        }

        this._frames++;
    }

    /** return true if glfw was close-requested */
    public boolean shouldClose() {
        return (GLFW.glfwWindowShouldClose(this._ptr));
    }

    /** get window GLFW pointer */
    public long getPointer() {
        return (this._ptr);
    }

    /** get mouse X coordinate */
    public double getMouseX() {
        return (this._mouseX);
    }

    /** get mouse Y coordinate */
    public double getMouseY() {
        return (this._mouseY);
    }

    public double getPrevMouseX() {
        return (this._prev_mouseX);
    }

    public double getPrevMouseY() {
        return (this._prev_mouseY);
    }

    /**
     * return mouse delta X since last cursor move was made and current position
     */
    public double getMouseDX() {
        return (this._mouseX - this._prev_mouseX);
    }

    /**
     * return mouse delta Y since last cursor move was made and current position
     */
    public double getMouseDY() {
        return (this._mouseY - this._prev_mouseY);
    }

    /** get total frames flushed */
    public long getTotalFramesFlushed() {
        return (this._frames);
    }

    public boolean isKeyPressed(int key) {
        return (GLFW.glfwGetKey(this.getPointer(), key) == GLFW.GLFW_PRESS);
    }

    public boolean isKeyReleased(int key) {
        return (GLFW.glfwGetKey(this.getPointer(), key) == GLFW.GLFW_RELEASE);
    }

    public boolean isMousePressed(int button) {
        return (GLFW.glfwGetMouseButton(this.getPointer(), button) == GLFW.GLFW_PRESS);
    }

    public boolean isMouseRightPressed() {
        return (GLFW.glfwGetMouseButton(this.getPointer(), GLFW.GLFW_MOUSE_BUTTON_RIGHT) == GLFW.GLFW_PRESS);
    }

    public boolean isMouseLeftPressed() {
        return (GLFW.glfwGetMouseButton(this.getPointer(), GLFW.GLFW_MOUSE_BUTTON_LEFT) == GLFW.GLFW_PRESS);
    }

    @Override
    public void invokeKeyPress(GLFWWindow glfwWindow, int key, int scancode, int mods) {
        if (key == GLFW.GLFW_KEY_ESCAPE) {
            this.close();
        }
    }

    public int getFPS() {
        return (this._fps);
    }

    public void setSize(int width, int height) {
        GLFW.glfwSetWindowSize(this.getPointer(), width, height);
    }

    public void close() {
        GLFW.glfwSetWindowShouldClose(this._ptr, true);
    }

    public boolean hasFocus() {
        return (this._focus);
    }

    public void focus(boolean focus) {
        if (focus) {
            GLFW.glfwFocusWindow(this.getPointer());
        }
    }
}