org.terasology.rendering.opengl.OpenGLUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.terasology.rendering.opengl.OpenGLUtils.java

Source

/*
 * Copyright 2016 MovingBlocks
 *
 * 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 org.terasology.rendering.opengl;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import static org.lwjgl.opengl.EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT;
import static org.lwjgl.opengl.EXTFramebufferObject.GL_FRAMEBUFFER_EXT;
import static org.lwjgl.opengl.EXTFramebufferObject.glBindFramebufferEXT;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL11.GL_MODELVIEW;
import static org.lwjgl.opengl.GL11.glPopMatrix;

public final class OpenGLUtils {
    private static int displayListQuad = -1;

    private OpenGLUtils() {
        // Utility class, no instance required
    }

    /**
     * Removes the rotation and scale part of the current OpenGL matrix.
     * Can be used to render billboards like particles.
     */
    public static void applyBillboardOrientation() {
        // Fetch the current modelview matrix
        final FloatBuffer model = BufferUtils.createFloatBuffer(16);
        GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, model);

        // And undo all rotations and scaling
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (i == j) {
                    model.put(i * 4 + j, 1.0f);
                } else {
                    model.put(i * 4 + j, 0.0f);
                }
            }
        }

        GL11.glLoadMatrix(model);
    }

    /**
     * Sets the viewport of the currently bound FBO to the dimensions of the FBO
     * given as parameter.
     *
     * @param fbo The FBO whose dimensions will be matched by the viewport of the currently bound FBO.
     */
    public static void setViewportToSizeOf(FBO fbo) {
        glViewport(0, 0, fbo.width(), fbo.height());
    }

    public static void setViewportToSizeOf(DefaultDynamicFBOs defaultDynamicFBO) {
        glViewport(0, 0, defaultDynamicFBO.width(), defaultDynamicFBO.height());
    }

    /**
     * Unbinds any currently bound FBO and binds the default Frame Buffer,
     * which is usually the Display (be it the full screen or a window).
     */
    public static void bindDisplay() {
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
    }

    /**
     * Once an FBO is bound, opengl commands will act on it, i.e. by drawing on it.
     * Meanwhile shaders might output not just colors but additional per-pixel data. This method establishes on which
     * of an FBOs attachments, subsequent opengl commands and shaders will draw on.
     *
     * @param fbo         The FBO holding the attachments to be set or unset for drawing.
     * @param color       If True the color buffer is set as drawable. If false subsequent commands and shaders won't be able to draw on it.
     * @param normal      If True the normal buffer is set as drawable. If false subsequent commands and shaders won't be able to draw on it.
     * @param lightBuffer If True the light buffer is set as drawable. If false subsequent commands and shaders won't be able to draw on it.
     */
    // TODO: verify if this can become part of the FBO.bind() method.
    public static void setRenderBufferMask(FBO fbo, boolean color, boolean normal, boolean lightBuffer) {
        if (fbo == null) {
            return;
        }

        int attachmentId = 0;

        IntBuffer bufferIds = BufferUtils.createIntBuffer(3);

        if (fbo.colorBufferTextureId != 0) {
            if (color) {
                bufferIds.put(GL_COLOR_ATTACHMENT0_EXT + attachmentId);
            }
            attachmentId++;
        }
        if (fbo.normalsBufferTextureId != 0) {
            if (normal) {
                bufferIds.put(GL_COLOR_ATTACHMENT0_EXT + attachmentId);
            }
            attachmentId++;
        }
        if (fbo.lightBufferTextureId != 0 && lightBuffer) {
            bufferIds.put(GL_COLOR_ATTACHMENT0_EXT + attachmentId);
        }

        bufferIds.flip();

        GL20.glDrawBuffers(bufferIds);
    }

    /**
     * Renders a quad filling the whole currently set viewport.
     */
    public static void renderFullscreenQuad() {
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glLoadIdentity();

        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();

        renderQuad();

        glPopMatrix();

        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();
    }

    /**
     * First sets a viewport and then renders a quad filling it.
     *
     * @param x              an integer representing the x coordinate (in pixels) of the origin of the viewport.
     * @param y              an integer representing the y coordinate (in pixels) of the origin of the viewport.
     * @param viewportWidth  an integer representing the width (in pixels) the viewport.
     * @param viewportHeight an integer representing the height (in pixels) the viewport.
     */
    // TODO: perhaps remove this method and make sure the viewport is set explicitly.
    // TODO: find a much more suitable name for this method
    public static void renderFullscreenQuad(int x, int y, int viewportWidth, int viewportHeight) {
        glViewport(x, y, viewportWidth, viewportHeight);
        renderFullscreenQuad();
    }

    // TODO: replace with a proper resident buffer with interleaved vertex and uv coordinates
    private static void renderQuad() {
        if (displayListQuad == -1) {
            displayListQuad = glGenLists(1);

            glNewList(displayListQuad, GL11.GL_COMPILE);

            glBegin(GL_QUADS);
            glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

            glTexCoord2d(0.0, 0.0);
            glVertex3i(-1, -1, -1);

            glTexCoord2d(1.0, 0.0);
            glVertex3i(1, -1, -1);

            glTexCoord2d(1.0, 1.0);
            glVertex3i(1, 1, -1);

            glTexCoord2d(0.0, 1.0);
            glVertex3i(-1, 1, -1);

            glEnd();

            glEndList();
        }

        glCallList(displayListQuad);
    }
}