-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds support for nested buffers; closes #2.
- Loading branch information
Showing
4 changed files
with
237 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
src/main/java/de/eskalon/commons/utils/graphics/GLUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* | ||
* Copyright 2020 damios | ||
* | ||
* 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 de.eskalon.commons.utils.graphics; | ||
|
||
import java.nio.ByteBuffer; | ||
import java.nio.ByteOrder; | ||
import java.nio.IntBuffer; | ||
|
||
import com.badlogic.gdx.Application.ApplicationType; | ||
import com.badlogic.gdx.Gdx; | ||
import com.badlogic.gdx.graphics.GL20; | ||
import com.badlogic.gdx.utils.GdxRuntimeException; | ||
|
||
/** | ||
* OpenGL utilities. | ||
* | ||
* @author damios | ||
*/ | ||
public class GLUtils { | ||
|
||
/** | ||
* The buffer used. A size of 64 bytes is required as at most 16 integer | ||
* elements can be returned. | ||
*/ | ||
private static final IntBuffer USED_INT_BUFF = ByteBuffer | ||
.allocateDirect(16 * Integer.BYTES).order(ByteOrder.nativeOrder()) | ||
.asIntBuffer(); | ||
|
||
/** | ||
* Returns the name of the currently bound framebuffer | ||
* ({@code GL_FRAMEBUFFER_BINDING}). | ||
* <p> | ||
* Doesn't work in WebGL! | ||
* | ||
* @return returns a single value, the name of the currently bound | ||
* framebuffer. The initial value is {@code 0}, indicating the | ||
* default framebuffer. | ||
* | ||
* @see @see <a href= "https://github.com/libgdx/libgdx/issues/4688">The | ||
* libGDX issue detailing the WebGL problems</a> | ||
*/ | ||
public static synchronized int getBoundFboHandle() { | ||
if (Gdx.app.getType() == ApplicationType.WebGL) | ||
throw new GdxRuntimeException( | ||
"This operation is not supported on WebGL."); | ||
|
||
IntBuffer intBuf = USED_INT_BUFF; | ||
Gdx.gl.glGetIntegerv(GL20.GL_FRAMEBUFFER_BINDING, intBuf); | ||
return intBuf.get(0); | ||
} | ||
|
||
/** | ||
* @return the current gl viewport ({@code GL_VIEWPORT}) as an array, | ||
* containing four values: the x and y window coordinates of the | ||
* viewport, followed by its width and height. | ||
*/ | ||
public static synchronized int[] getViewport() { | ||
IntBuffer intBuf = USED_INT_BUFF; | ||
Gdx.gl.glGetIntegerv(GL20.GL_VIEWPORT, intBuf); | ||
|
||
return new int[] { intBuf.get(0), intBuf.get(1), intBuf.get(2), | ||
intBuf.get(3) }; | ||
} | ||
|
||
} |
149 changes: 149 additions & 0 deletions
149
src/main/java/de/eskalon/commons/utils/graphics/NestableFrameBuffer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
/* | ||
* Copyright 2020 damios | ||
* | ||
* 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 de.eskalon.commons.utils.graphics; | ||
|
||
import com.badlogic.gdx.Gdx; | ||
import com.badlogic.gdx.graphics.GL20; | ||
import com.badlogic.gdx.graphics.Pixmap; | ||
import com.badlogic.gdx.graphics.Pixmap.Format; | ||
import com.badlogic.gdx.graphics.Texture; | ||
import com.badlogic.gdx.graphics.glutils.FrameBuffer; | ||
import com.badlogic.gdx.graphics.glutils.GLFrameBuffer; | ||
import com.badlogic.gdx.graphics.glutils.GLFrameBuffer.FrameBufferBuilder; | ||
|
||
/** | ||
* An implementation of the libGDX {@link FrameBuffer} that supports nested | ||
* framebuffers. This allows using multiple framebuffers inside each other: | ||
* | ||
* <pre> | ||
* {@code | ||
* fbo0.begin(); | ||
* // Stuff is rendered into fbo0 | ||
* fbo1.begin(); | ||
* // Stuff is rendered into fbo1 | ||
* fbo1.end(); | ||
* // Stuff is rendered into fbo0 again | ||
* // this is where the default FrameBuffer implementation would break | ||
* fbo0.end(); | ||
* } | ||
* </pre> | ||
* | ||
* @author damios | ||
* @see <a href= | ||
* "https://github.com/crykn/libgdx-screenmanager/wiki/Custom-FrameBuffer-implementation">The | ||
* wiki entry detailing the reasoning behind the implementation</a> | ||
*/ | ||
public class NestableFrameBuffer extends FrameBuffer { | ||
|
||
private int previousFBOHandle = -1; | ||
private int[] previousViewport = new int[4]; | ||
private boolean isActive = false; | ||
|
||
/** | ||
* Creates a new NestableFrameBuffer having the given dimensions and | ||
* potentially a depth buffer attached. | ||
* | ||
* @param format | ||
* the format of the color buffer; according to the OpenGL ES 2.0 | ||
* spec, only {@link Format#RGB565}, {@link Format#RGBA4444} and | ||
* {@link Format#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 | ||
*/ | ||
public NestableFrameBuffer(Pixmap.Format format, int width, int height, | ||
boolean hasDepth) { | ||
super(format, width, height, hasDepth, false); | ||
} | ||
|
||
protected NestableFrameBuffer( | ||
GLFrameBufferBuilder<? extends GLFrameBuffer<Texture>> bufferBuilder) { | ||
super(bufferBuilder); | ||
} | ||
|
||
/** | ||
* Binds the frame buffer and sets the viewport accordingly, so everything | ||
* gets drawn to it. | ||
*/ | ||
@Override | ||
public void begin() { | ||
if (isActive) | ||
throw new IllegalStateException( | ||
"end() has to be called before another draw can begin!"); | ||
isActive = true; | ||
|
||
previousFBOHandle = GLUtils.getBoundFboHandle(); | ||
bind(); | ||
|
||
previousViewport = GLUtils.getViewport(); | ||
setFrameBufferViewport(); | ||
} | ||
|
||
/** | ||
* Unbinds the framebuffer, all drawing will be performed to the | ||
* {@linkplain #previousFBOHandle previous framebuffer} (usually the normal | ||
* one) from here on. | ||
*/ | ||
@Override | ||
public void end() { | ||
end(previousViewport[0], previousViewport[1], previousViewport[2], | ||
previousViewport[3]); | ||
} | ||
|
||
/** | ||
* Unbinds the framebuffer and sets viewport sizes, all drawing will be | ||
* performed to the {@linkplain #previousFBOHandle previous framebuffer} | ||
* (usually the normal one) 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 | ||
*/ | ||
@Override | ||
public void end(int x, int y, int width, int height) { | ||
if (!isActive) | ||
throw new IllegalStateException("begin() has to be called first!"); | ||
isActive = false; | ||
|
||
if (GLUtils.getBoundFboHandle() != framebufferHandle) { | ||
throw new IllegalStateException( | ||
"The currently bound framebuffer doesn't match this one. Make sure the nested framebuffers are closed in the same order they were opened in! "); | ||
} | ||
|
||
Gdx.gl20.glBindFramebuffer(GL20.GL_FRAMEBUFFER, previousFBOHandle); | ||
Gdx.gl20.glViewport(x, y, width, height); | ||
} | ||
|
||
public static class NestableFrameBufferBuilder extends FrameBufferBuilder { | ||
public NestableFrameBufferBuilder(int width, int height) { | ||
super(width, height); | ||
} | ||
|
||
@Override | ||
public FrameBuffer build() { | ||
return new NestableFrameBuffer(this); | ||
} | ||
} | ||
|
||
} |