All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.badlogic.gdx.graphics.glutils.GLFrameBuffer Maven / Gradle / Ivy

There is a newer version: 1.12.1
Show newest version
/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 *
 * 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 com.badlogic.gdx.graphics.glutils;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Map;

import com.badlogic.gdx.Application;
import com.badlogic.gdx.Application.ApplicationType;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GLTexture;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.GdxRuntimeException;

/** 

* Encapsulates OpenGL ES 2.0 frame buffer objects. This is a simple helper class which should cover most FBO uses. It will * automatically create a gltexture for the color attachment and a renderbuffer for the depth buffer. You can get a hold of the * gltexture by {@link GLFrameBuffer#getColorBufferTexture()}. This class will only work with OpenGL ES 2.0. *

* *

* FrameBuffers are managed. In case of an OpenGL context loss, which only happens on Android when a user switches to another * application or receives an incoming call, the framebuffer will be automatically recreated. *

* *

* A FrameBuffer must be disposed if it is no longer needed *

* * @author mzechner, realitix */ public class GLFrameBuffer implements Disposable { /** the frame buffers **/ private final static Map> buffers = new HashMap>(); /** the color buffer texture **/ protected T colorTexture; /** the default framebuffer handle, a.k.a screen. */ private static int defaultFramebufferHandle; /** true if we have polled for the default handle already. */ private static boolean defaultFramebufferHandleInitialized = false; /** the framebuffer handle **/ private int framebufferHandle; /** the depthbuffer render object handle **/ private int depthbufferHandle; /** the stencilbuffer render object handle **/ private int stencilbufferHandle; /** width **/ protected final int width; /** height **/ protected final int height; /** depth **/ protected final boolean hasDepth; /** stencil **/ protected final boolean hasStencil; /** format **/ protected final Pixmap.Format format; /** Creates a new FrameBuffer having the given dimensions and potentially a depth buffer attached. * * @param format * @param width * @param height * @param hasDepth */ public GLFrameBuffer (Pixmap.Format format, int width, int height, boolean hasDepth) { this(format, width, height, hasDepth, false); } /** Creates a new FrameBuffer having the given dimensions and potentially a depth and a stencil buffer attached. * * @param format the format of the color buffer; according to the OpenGL ES 2.0 spec, only RGB565, RGBA4444 and RGB5_A1 are * color-renderable * @param width the width of the framebuffer in pixels * @param height the height of the framebuffer in pixels * @param hasDepth whether to attach a depth buffer * @throws com.badlogic.gdx.utils.GdxRuntimeException in case the FrameBuffer could not be created */ public GLFrameBuffer (Pixmap.Format format, int width, int height, boolean hasDepth, boolean hasStencil) { this.width = width; this.height = height; this.format = format; this.hasDepth = hasDepth; this.hasStencil = hasStencil; build(); addManagedFrameBuffer(Gdx.app, this); } /** Override this method in a derived class to set up the backing texture as you like. */ protected void setupTexture () { throw new GdxRuntimeException("Texture must be setup"); } private void build () { GL20 gl = Gdx.gl20; // iOS uses a different framebuffer handle! (not necessarily 0) if (!defaultFramebufferHandleInitialized) { defaultFramebufferHandleInitialized = true; if (Gdx.app.getType() == ApplicationType.iOS) { IntBuffer intbuf = ByteBuffer.allocateDirect(16 * Integer.SIZE / 8).order(ByteOrder.nativeOrder()).asIntBuffer(); gl.glGetIntegerv(GL20.GL_FRAMEBUFFER_BINDING, intbuf); defaultFramebufferHandle = intbuf.get(0); } else { defaultFramebufferHandle = 0; } } setupTexture(); framebufferHandle = gl.glGenFramebuffer(); if (hasDepth) { depthbufferHandle = gl.glGenRenderbuffer(); } if (hasStencil) { stencilbufferHandle = gl.glGenRenderbuffer(); } gl.glBindTexture(GL20.GL_TEXTURE_2D, colorTexture.getTextureObjectHandle()); if (hasDepth) { gl.glBindRenderbuffer(GL20.GL_RENDERBUFFER, depthbufferHandle); gl.glRenderbufferStorage(GL20.GL_RENDERBUFFER, GL20.GL_DEPTH_COMPONENT16, colorTexture.getWidth(), colorTexture.getHeight()); } if (hasStencil) { gl.glBindRenderbuffer(GL20.GL_RENDERBUFFER, stencilbufferHandle); gl.glRenderbufferStorage(GL20.GL_RENDERBUFFER, GL20.GL_STENCIL_INDEX8, colorTexture.getWidth(), colorTexture.getHeight()); } gl.glBindFramebuffer(GL20.GL_FRAMEBUFFER, framebufferHandle); gl.glFramebufferTexture2D(GL20.GL_FRAMEBUFFER, GL20.GL_COLOR_ATTACHMENT0, GL20.GL_TEXTURE_2D, colorTexture.getTextureObjectHandle(), 0); if (hasDepth) { gl.glFramebufferRenderbuffer(GL20.GL_FRAMEBUFFER, GL20.GL_DEPTH_ATTACHMENT, GL20.GL_RENDERBUFFER, depthbufferHandle); } if (hasStencil) { gl.glFramebufferRenderbuffer(GL20.GL_FRAMEBUFFER, GL20.GL_STENCIL_ATTACHMENT, GL20.GL_RENDERBUFFER, stencilbufferHandle); } int result = gl.glCheckFramebufferStatus(GL20.GL_FRAMEBUFFER); gl.glBindRenderbuffer(GL20.GL_RENDERBUFFER, 0); gl.glBindTexture(GL20.GL_TEXTURE_2D, 0); gl.glBindFramebuffer(GL20.GL_FRAMEBUFFER, defaultFramebufferHandle); if (result != GL20.GL_FRAMEBUFFER_COMPLETE) { colorTexture.dispose(); if (hasDepth) gl.glDeleteRenderbuffer(depthbufferHandle); if (hasStencil) gl.glDeleteRenderbuffer(stencilbufferHandle); gl.glDeleteFramebuffer(framebufferHandle); if (result == GL20.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) throw new IllegalStateException("frame buffer couldn't be constructed: incomplete attachment"); if (result == GL20.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS) throw new IllegalStateException("frame buffer couldn't be constructed: incomplete dimensions"); if (result == GL20.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) throw new IllegalStateException("frame buffer couldn't be constructed: missing attachment"); if (result == GL20.GL_FRAMEBUFFER_UNSUPPORTED) throw new IllegalStateException("frame buffer couldn't be constructed: unsupported combination of formats"); throw new IllegalStateException("frame buffer couldn't be constructed: unknown error " + result); } } /** Releases all resources associated with the FrameBuffer. */ @Override public void dispose () { GL20 gl = Gdx.gl20; colorTexture.dispose(); if (hasDepth) gl.glDeleteRenderbuffer(depthbufferHandle); if (hasStencil) gl.glDeleteRenderbuffer(stencilbufferHandle); gl.glDeleteFramebuffer(framebufferHandle); if (buffers.get(Gdx.app) != null) buffers.get(Gdx.app).removeValue(this, true); } /** Makes the frame buffer current so everything gets drawn to it. */ public void bind () { Gdx.gl20.glBindFramebuffer(GL20.GL_FRAMEBUFFER, framebufferHandle); } /** Unbinds the framebuffer, all drawing will be performed to the normal framebuffer from here on. */ public static void unbind () { Gdx.gl20.glBindFramebuffer(GL20.GL_FRAMEBUFFER, defaultFramebufferHandle); } /** Binds the frame buffer and sets the viewport accordingly, so everything gets drawn to it. */ public void begin () { bind(); setFrameBufferViewport(); } /** Sets viewport to the dimensions of framebuffer. Called by {@link #begin()}. */ protected void setFrameBufferViewport () { Gdx.gl20.glViewport(0, 0, colorTexture.getWidth(), colorTexture.getHeight()); } /** Unbinds the framebuffer, all drawing will be performed to the normal framebuffer from here on. */ public void end () { end(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); } /** Unbinds the framebuffer and sets viewport sizes, all drawing will be performed to the normal framebuffer from here on. * * @param x the x-axis position of the viewport in pixels * @param y the y-asis position of the viewport in pixels * @param width the width of the viewport in pixels * @param height the height of the viewport in pixels */ public void end (int x, int y, int width, int height) { unbind(); Gdx.gl20.glViewport(x, y, width, height); } /** @return the gl texture */ public T getColorBufferTexture () { return colorTexture; } /** @return The OpenGL handle of the framebuffer (see {@link GL20#glGenFramebuffer()}) */ public int getFramebufferHandle () { return framebufferHandle; } /** @return The OpenGL handle of the (optional) depth buffer (see {@link GL20#glGenRenderbuffer()}) */ public int getDepthBufferHandle () { return depthbufferHandle; } /** @return The OpenGL handle of the (optional) stencil buffer (see {@link GL20#glGenRenderbuffer()}) */ public int getStencilBufferHandle () { return stencilbufferHandle; } /** @return the height of the framebuffer in pixels */ public int getHeight () { return colorTexture.getHeight(); } /** @return the width of the framebuffer in pixels */ public int getWidth () { return colorTexture.getWidth(); } /** @return the depth of the framebuffer in pixels (if applicable) */ public int getDepth () { return colorTexture.getDepth(); } private static void addManagedFrameBuffer (Application app, GLFrameBuffer frameBuffer) { Array managedResources = buffers.get(app); if (managedResources == null) managedResources = new Array(); managedResources.add(frameBuffer); buffers.put(app, managedResources); } /** Invalidates all frame buffers. This can be used when the OpenGL context is lost to rebuild all managed frame buffers. This * assumes that the texture attached to this buffer has already been rebuild! Use with care. */ public static void invalidateAllFrameBuffers (Application app) { if (Gdx.gl20 == null) return; Array bufferArray = buffers.get(app); if (bufferArray == null) return; for (int i = 0; i < bufferArray.size; i++) { bufferArray.get(i).build(); } } public static void clearAllFrameBuffers (Application app) { buffers.remove(app); } public static StringBuilder getManagedStatus (final StringBuilder builder) { builder.append("Managed buffers/app: { "); for (Application app : buffers.keySet()) { builder.append(buffers.get(app).size); builder.append(" "); } builder.append("}"); return builder; } public static String getManagedStatus () { return getManagedStatus(new StringBuilder()).toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy