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