Java tutorial
/******************************************************************************** * * Copyright 2014 Theodor Angergard * * 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 se.angergard.engine.graphics; import java.nio.*; import org.lwjgl.opengl.*; import se.angergard.engine.display.*; import se.angergard.engine.interfaces.*; public class FrameBuffer implements Disposable { public FrameBuffer(int width, int height, boolean hasDepth, boolean hasStencil) { this.width = width; this.height = height; if ((width + height) % 4 != 0.0) { new Exception("Width + Height must be divisible by 4"); } frameBufferID = GL30.glGenFramebuffers(); GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID); if (hasDepth && hasStencil) { depthAndStencilBufferID = GL30.glGenRenderbuffers(); GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthAndStencilBufferID); GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH24_STENCIL8, width, height); GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, depthAndStencilBufferID); GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, 0); } else if (hasDepth) { depthBufferID = GL30.glGenRenderbuffers(); GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, depthBufferID); GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_DEPTH_COMPONENT32F, width, height); GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL30.GL_RENDERBUFFER, depthBufferID); GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, 0); } else if (hasStencil) { stencilBufferID = GL30.glGenRenderbuffers(); GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, stencilBufferID); GL30.glRenderbufferStorage(GL30.GL_RENDERBUFFER, GL30.GL_STENCIL_INDEX16, width, height); GL30.glFramebufferRenderbuffer(GL30.GL_FRAMEBUFFER, GL30.GL_STENCIL_ATTACHMENT, GL30.GL_RENDERBUFFER, stencilBufferID); GL30.glBindRenderbuffer(GL30.GL_RENDERBUFFER, 0); } colorTexture = GL11.glGenTextures(); GL11.glBindTexture(GL11.GL_TEXTURE_2D, colorTexture); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null); GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D, colorTexture, 0); int result = GL30.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER); GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0); if (result != GL30.GL_FRAMEBUFFER_COMPLETE) { if (result == GL30.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) { new Exception("Frame Buffer Error: incomplete attachment").printStackTrace(); } if (result == GL30.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER) { new Exception("Frame Buffer Error: incomplete draw buffer").printStackTrace(); } if (result == GL30.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) { new Exception("Frame Buffer Error: missing attachment").printStackTrace(); } if (result == GL30.GL_FRAMEBUFFER_UNSUPPORTED) { new Exception("Frame Buffer Error: unsupported combination of formats").printStackTrace(); } if (result == GL30.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE) { new Exception("Frame Buffer Error: incomplete multisample").printStackTrace(); } if (result == GL30.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER) { new Exception("Frame Buffer Error: incomplete read buffer").printStackTrace(); } new Exception("frame buffer couldn't be constructed: unknown error " + result).printStackTrace(); } RenderUtil.unbindFrameBuffer(); RenderUtil.unbindTexture(); frameBufferShader = new ShaderProgram().createDefault2DShader(); } private ShaderProgram frameBufferShader; private int colorTexture; private int width, height; private int frameBufferID, depthBufferID, stencilBufferID, depthAndStencilBufferID; public void setShaderProgram(ShaderProgram shaderProgram) { this.frameBufferShader = shaderProgram; } public ShaderProgram getShaderProgram() { return frameBufferShader; } public void begin() { GL11.glViewport(0, 0, width, height); GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, frameBufferID); RenderUtil.clearScreen(); } public void end() { GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0); GL11.glViewport(0, 0, Display.getWidth(), Display.getHeight()); } public int getColorTexture() { return colorTexture; } public int getWidth() { return width; } public int getHeight() { return height; } @Override public void dispose() { GL11.glDeleteTextures(colorTexture); if (depthBufferID == 0 && stencilBufferID == 0) { GL30.glDeleteRenderbuffers(depthAndStencilBufferID); } else if (depthBufferID != 0) { GL30.glDeleteRenderbuffers(depthBufferID); } else if (stencilBufferID != 0) { GL30.glDeleteRenderbuffers(stencilBufferID); } GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0); GL30.glDeleteFramebuffers(frameBufferID); } }