net.kubin.game.Game.java Source code

Java tutorial

Introduction

Here is the source code for net.kubin.game.Game.java

Source

/*******************************************************************************
 * Copyright 2012 Martijn Courteaux <martijn.courteaux@skynet.be>
 *
 * 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 net.kubin.game;

import de.matthiasmann.twl.GUI;
import de.matthiasmann.twl.renderer.lwjgl.LWJGLRenderer;
import de.matthiasmann.twl.theme.ThemeManager;
import static org.lwjgl.opengl.GL11.*;

import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.kubin.Kubin;
import net.kubin.blocks.BlockJSONLoader;

import net.kubin.blocks.BlockManager;
import net.kubin.game.PerformanceMonitor.Operation;
import net.kubin.items.ItemXMLLoader;
import net.kubin.math.MathHelper;
import net.kubin.math.Vec3f;
import net.kubin.rendering.BufferManager;
import net.kubin.rendering.GLFont;
import net.kubin.rendering.GLUtils;
import net.kubin.world.World;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.NVFogDistance;

public class Game {
    private World _world;
    private int _fps = Kubin._fps;
    private float _step;
    private int _sleepTimeMillis;
    private static Configuration _configuration = Kubin.getConfiguration();
    private static Game __instance;
    private int[] _fpsDataBuffer = Kubin._fpsDataBuffer;
    private float _averageFPS = Kubin._averageFPS;

    public static boolean RENDER_INFORMATION_OVERLAY = false;

    public static Game getInstance() {
        if (__instance == null) {
            __instance = new Game();
        }

        return __instance;
    }

    public GUI gui;
    public LWJGLRenderer renderer;
    public ThemeManager theme;

    public void init() throws IOException {

        System.out.println("LWJGL Version: " + Sys.getVersion());
        System.out.println("GPU: " + Display.getAdapter());

        initOpenGL();
        loadTextures();
        loadFonts();
        //loadItems();
        loadBlocks();
        //loadSpecialStuff();
        Mouse.setGrabbed(true);
    }

    public void initOpenGL() {
        // init OpenGL
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, 800, 600, 0, 1, 300);
        glMatrixMode(GL_MODELVIEW);

        GL11.glShadeModel(GL11.GL_SMOOTH);

        Vec3f fog = Kubin.getConfiguration().getFogColor();

        glClearColor(fog.x(), fog.y(), fog.z(), 1.0f);
        glEnable(GL_TEXTURE_2D);
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

        // glEnable(GL_DEPTH_TEST);
        // glDepthFunc(GL_ALWAYS);

        glEnable(GL_CULL_FACE);

        glEnable(GL_FOG);
        glFog(GL_FOG_COLOR, GLUtils.wrapDirect(fog.x(), fog.y(), fog.z(), 1.0f));
        glFogi(GL_FOG_MODE, GL11.GL_LINEAR);
        glFogf(GL_FOG_START, Kubin.getConfiguration().getViewingDistance() * 0.55f);
        glFogf(GL_FOG_END, Kubin.getConfiguration().getViewingDistance());
        glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, NVFogDistance.GL_EYE_RADIAL_NV);
        glHint(GL_FOG_HINT, GL_NICEST);

        System.out.println("VBO Supported: " + GLUtils.isVBOSupported());

        /* Instantiate the BufferManager */
        BufferManager.getInstance();
    }

    private void loadSpecialStuff() {
        try {
            Class.forName("net.kubin.rendering.particles.Smoke");
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    public float getFPS() {
        return _fps;
    }

    public float getStep() {
        return _step;
    }

    public void update() {
        if (_world != null) {
            _world.update();
        }

        BufferManager.getInstance().deleteQueuedBuffers();
    }

    public void render() {
        // Clear the screen and depth buffer
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        if (_world != null) {
            _world.render();
        }

        if (RENDER_INFORMATION_OVERLAY) {
            renderOnScreenInfo();
        }
    }

    private void renderOnScreenInfo() {
        GLFont infoFont = FontStorage.getFont("Monospaced_20");
        glColor3f(1, 1, 1);

        /* Top Left Info */
        infoFont.print(4, _configuration.getHeight() - 20, String.format("FPS: %5.1f", getAverageFPS()));
        infoFont.print(4, _configuration.getHeight() - 20 - 15,
                "Sleeping: " + String.format("%4d", Game.getInstance().getSleepTime()));
        infoFont.print(4, _configuration.getHeight() - 20 - 30,
                "Heap Size: " + MathHelper.bytesToMagaBytes(Runtime.getRuntime().totalMemory()) + " MB");
        infoFont.print(4, _configuration.getHeight() - 20 - 45, "Heap Use:  " + MathHelper
                .bytesToMagaBytes(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) + " MB");
        infoFont.print(4, _configuration.getHeight() - 20 - 60,
                "Buffers: " + BufferManager.getInstance().getAliveBuffers());

        Operation[] ops = Operation.values();

        for (int i = 0; i < ops.length; ++i) {
            String name = ops[i].name();
            infoFont.print(_configuration.getWidth() - 200, _configuration.getHeight() - 20 - 15 * i,
                    String.format("%-20s %7.3f", name, PerformanceMonitor.getInstance().get(ops[i])));
        }

        infoFont.print(Kubin.getConfiguration().getWidth() - 260, 0,
                _world.getActivePlayer().getLookDir().toString());
        infoFont.print(Kubin.getConfiguration().getWidth() - 100, 0,
                "Colliding: " + _world.getActivePlayer().isColliding);

    }

    public void initOverlayRendering() {

        Configuration conf = Kubin.getConfiguration();

        glDisable(GL_FOG);

        glClear(GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, conf.getWidth(), 0, conf.getHeight(), -100, 100);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        glEnable(GL_COLOR_MATERIAL);
        glEnable(GL_ALPHA_TEST);
        glDisable(GL_CULL_FACE);
        glDisable(GL_DEPTH_TEST);
    }

    public void initSceneRendering() {

        glDisable(GL_BLEND);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
        glEnable(GL_CULL_FACE);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glEnable(GL_FOG);
    }

    public void renderTransculentOverlayLayer() {
        glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
        glDisable(GL_TEXTURE_2D);
        glBegin(GL_QUADS);
        glVertex2i(0, 0);
        glVertex2i(_configuration.getWidth(), 0);
        glVertex2i(_configuration.getWidth(), _configuration.getHeight());
        glVertex2i(0, _configuration.getWidth());
        glEnd();
    }

    public void startGameLoop() {

        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);

        while (!Display.isCloseRequested()) {
            if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
                BufferManager.getInstance().deleteQueuedBuffers();
                BlockManager.getInstance().release();
                TextureStorage.release();
                FontStorage.release();
                Display.destroy();
            }

            if (Display.wasResized()) {
                handleResize();
            }

            long startTiming = System.nanoTime();
            _step = 1.0f / _fps;

            /* Update */
            PerformanceMonitor.getInstance().start(Operation.UPDATE);
            update();
            PerformanceMonitor.getInstance().stop(Operation.UPDATE);

            /* Render */
            PerformanceMonitor.getInstance().start(Operation.RENDER_ALL);
            render();
            //gui.update();
            Display.update();
            PerformanceMonitor.getInstance().stop(Operation.RENDER_ALL);

            long stopTiming = System.nanoTime();

            long frameTimeNanos = (stopTiming - startTiming);
            long desiredFrameTimeNanos = 1000000000L;

            if (_configuration.getVSync()) {
                // desiredFrameTimeNanos /= 1;
            } else {
                desiredFrameTimeNanos /= _configuration.getFPS();
            }

            long diff = desiredFrameTimeNanos - frameTimeNanos;

            if (frameTimeNanos < desiredFrameTimeNanos) {
                if (!_configuration.getVSync()) {
                    try {
                        _sleepTimeMillis = (int) (diff / 1000000L);
                        Thread.sleep(_sleepTimeMillis, (int) (diff % 1000000L));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            } else {
                _sleepTimeMillis = 0;
            }

            _fps = (int) (1000000000.0f / (frameTimeNanos + (_sleepTimeMillis * 1000000L)));

            /* Average FPS System */
            float fpsSum = _fps;

            for (int i = 0; i < _fpsDataBuffer.length - 1; ++i) {
                _fpsDataBuffer[i] = _fpsDataBuffer[i + 1];
                fpsSum += _fpsDataBuffer[i];
            }

            _fpsDataBuffer[_fpsDataBuffer.length - 1] = _fps;
            fpsSum /= _fpsDataBuffer.length;
            _averageFPS = fpsSum;
        }

        if (_world != null) {
            try {
                getWorld().save();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        BufferManager.getInstance().deleteQueuedBuffers();
        BlockManager.getInstance().release();
        TextureStorage.release();
        FontStorage.release();
        //gui.destroy();
        //theme.destroy();
        Display.destroy();

    }

    public void handleResize() {
        //Prevent negative UI sizes
        if (Display.getWidth() < 250) {
            return;
        }

        if (Display.getHeight() < 250) {
            return;
        }

        //Resize the UI and Viewport
        _configuration.setDisplaySettings(Display.getWidth(), Display.getHeight(), Display.isFullscreen());
        GL11.glViewport(0, 0, Display.getWidth(), Display.getHeight());
        getWorld().handleDisplayResize();
    }

    private void loadTextures() throws IOException {
        TextureStorage.setTexturePack(Kubin.getConfiguration().getTexturePack());
        TextureStorage.loadTexture("blocks", "PNG", "blocks.png");
        TextureStorage.loadTexture("environment.clouds", "PNG", "environment/clouds.png");
        TextureStorage.loadTexture("gui.gui", "PNG", "gui/gui.png");
        TextureStorage.loadTexture("gui.inventory", "PNG", "gui/inventory.png");
    }

    private void loadFonts() throws IOException {
        FontStorage.loadFont("Monospaced_20", "novamono.ttf", 22);
        FontStorage.loadFont("InventoryAmount", "visitor1.ttf", 14);
    }

    private void loadItems() {
        try {
            ItemXMLLoader.parseXML();
        } catch (Exception ex) {
            Logger.getLogger(Game.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void loadBlocks() {
        try {
            //BlockXMLLoader.parseXML();
            BlockJSONLoader.parseJSON();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setWorld(World world) {
        this._world = world;
    }

    public World getWorld() {
        return this._world;
    }

    /**
     * Returns the sleeptime in milliseconds for the last frame.
     *
     * @return
     */
    public int getSleepTime() {
        return _sleepTimeMillis;
    }

    public float getAverageFPS() {
        return _averageFPS;
    }

    public static final int FILE_BASE_APPLICATION = 0x01;
    public static final int FILE_BASE_USER_DATA = 0x02;

    public File getRelativeFile(int fileBase, String string) {
        if (string.contains("${world}")) {
            string = string.replace("${world}", getWorld().getWorldName());
        }

        switch (fileBase) {
        case FILE_BASE_USER_DATA:
            return new File(getUserDataFolder(), string);

        case FILE_BASE_APPLICATION:
        default:
            return new File(string);
        }
    }

    private File getUserHome() {
        return new File(System.getProperty("user.home"));
    }

    public File getUserDataFolder() {
        String os = System.getProperty("os.name").toLowerCase();
        File f = null;

        if (!Kubin.USE_USER_DATA_DIR) {
            f = new File(".kubin");
        } else {
            if (os.contains("mac")) {
                f = new File(getUserHome(), "Library/Application Support/kubin");
            } else if (os.contains("inux") || os.contains("nix")) {
                f = new File(getUserHome(), ".kubin");
            } else if (os.contains("win")) {
                f = new File(new File(System.getenv("APPDATA")), ".kubin");
            }
        }

        f.mkdir();
        return f;
    }
}