/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/
package com.ardor3d.renderer.lwjgl;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;
import org.lwjgl.opengl.ARBDepthTexture;
import org.lwjgl.opengl.ARBDrawBuffers;
import org.lwjgl.opengl.EXTFramebufferBlit;
import org.lwjgl.opengl.EXTFramebufferMultisample;
import org.lwjgl.opengl.EXTFramebufferObject;
import org.lwjgl.opengl.GL11;
import com.ardor3d.framework.Scene;
import com.ardor3d.image.Texture;
import com.ardor3d.image.Texture.Type;
import com.ardor3d.image.TextureCubeMap;
import com.ardor3d.image.TextureCubeMap.Face;
import com.ardor3d.math.type.ReadOnlyColorRGBA;
import com.ardor3d.renderer.AbstractFBOTextureRenderer;
import com.ardor3d.renderer.ContextCapabilities;
import com.ardor3d.renderer.ContextManager;
import com.ardor3d.renderer.RenderContext;
import com.ardor3d.renderer.Renderer;
import com.ardor3d.renderer.TextureRendererFactory;
import com.ardor3d.renderer.state.RenderState;
import com.ardor3d.renderer.state.record.RendererRecord;
import com.ardor3d.renderer.state.record.TextureRecord;
import com.ardor3d.renderer.state.record.TextureStateRecord;
import com.ardor3d.scene.state.lwjgl.LwjglTextureStateUtil;
import com.ardor3d.scene.state.lwjgl.util.LwjglTextureUtil;
import com.ardor3d.scenegraph.Spatial;
import com.ardor3d.util.Ardor3dException;
import com.ardor3d.util.TextureKey;
import com.ardor3d.util.geom.BufferUtils;
/**
* <p>
* This class is used by Ardor3D's LWJGL implementation to render textures. Users should <b>not</b> create this class
* directly.
* </p>
*
* @see TextureRendererFactory
*/
public class LwjglTextureRenderer extends AbstractFBOTextureRenderer {
private static final Logger logger = Logger.getLogger(LwjglTextureRenderer.class.getName());
public LwjglTextureRenderer(final int width, final int height, final int depthBits, final int samples,
final Renderer parentRenderer, final ContextCapabilities caps) {
super(width, height, depthBits, samples, parentRenderer, caps);
if (caps.getMaxFBOColorAttachments() > 1) {
_attachBuffer = BufferUtils.createIntBuffer(caps.getMaxFBOColorAttachments());
for (int i = 0; i < caps.getMaxFBOColorAttachments(); i++) {
_attachBuffer.put(EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT + i);
}
}
}
/**
* <code>setupTexture</code> initializes a new Texture object for use with TextureRenderer. Generates a valid OpenGL
* texture id for this texture and initializes the data type for the texture.
*/
public void setupTexture(final Texture tex) {
if (tex.getType() != Type.TwoDimensional && tex.getType() != Type.CubeMap) {
throw new IllegalArgumentException("Texture type not supported: " + tex.getType());
}
final RenderContext context = ContextManager.getCurrentContext();
final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(RenderState.StateType.Texture);
// check if we are already setup... if so, throw error.
if (tex.getTextureKey() == null) {
tex.setTextureKey(TextureKey.getRTTKey(tex.getMinificationFilter()));
} else if (tex.getTextureIdForContext(context.getGlContextRep()) != 0) {
throw new Ardor3dException("Texture is already setup and has id.");
}
// Create the texture
final IntBuffer ibuf = BufferUtils.createIntBuffer(1);
GL11.glGenTextures(ibuf);
final int textureId = ibuf.get(0);
tex.setTextureIdForContext(context.getGlContextRep(), textureId);
LwjglTextureStateUtil.doTextureBind(tex, 0, true);
// Initialize our texture with some default data.
final int internalFormat = LwjglTextureUtil.getGLInternalFormat(tex.getTextureStoreFormat());
final int dataFormat = LwjglTextureUtil.getGLPixelFormatFromStoreFormat(tex.getTextureStoreFormat());
final int pixelDataType = LwjglTextureUtil.getGLPixelDataType(tex.getRenderedTexturePixelDataType());
if (tex.getType() == Type.TwoDimensional) {
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, internalFormat, _width, _height, 0, dataFormat, pixelDataType,
(ByteBuffer) null);
} else {
for (final Face face : Face.values()) {
GL11.glTexImage2D(LwjglTextureStateUtil.getGLCubeMapFace(face), 0, internalFormat, _width, _height, 0,
dataFormat, pixelDataType, (ByteBuffer) null);
}
}
// Initialize mipmapping for this texture, if requested
if (tex.getMinificationFilter().usesMipMapLevels()) {
EXTFramebufferObject.glGenerateMipmapEXT(LwjglTextureStateUtil.getGLType(tex.getType()));
}
// Setup filtering and wrap
final TextureRecord texRecord = record.getTextureRecord(textureId, tex.getType());
LwjglTextureStateUtil.applyFilter(tex, texRecord, 0, record, context.getCapabilities());
LwjglTextureStateUtil.applyWrap(tex, texRecord, 0, record, context.getCapabilities());
logger.fine("setup fbo tex with id " + textureId + ": " + _width + "," + _height);
}
public void render(final Spatial spat, final List<Texture> texs, final int clear) {
render(null, spat, null, texs, clear);
}
public void render(final List<? extends Spatial> spat, final List<Texture> texs, final int clear) {
render(spat, null, null, texs, clear);
}
@Override
public void render(final Scene scene, final List<Texture> texs, final int clear) {
render(null, null, scene, texs, clear);
}
private void render(final List<? extends Spatial> toDrawA, final Spatial toDrawB, final Scene toDrawC,
final List<Texture> texs, final int clear) {
final int maxDrawBuffers = ContextManager.getCurrentContext().getCapabilities().getMaxFBOColorAttachments();
// if we only support 1 draw buffer at a time anyway, we'll have to render to each texture individually...
if (maxDrawBuffers == 1 || texs.size() == 1) {
try {
ContextManager.getCurrentContext().pushFBOTextureRenderer(this);
for (int i = 0; i < texs.size(); i++) {
final Texture tex = texs.get(i);
setupForSingleTexDraw(tex);
if (_samples > 0 && _supportsMultisample) {
setMSFBO();
}
switchCameraIn(clear);
if (toDrawA != null) {
doDraw(toDrawA);
} else if (toDrawB != null) {
doDraw(toDrawB);
} else {
doDraw(toDrawC);
}
switchCameraOut();
if (_samples > 0 && _supportsMultisample) {
blitMSFBO();
}
takedownForSingleTexDraw(tex);
}
} finally {
ContextManager.getCurrentContext().popFBOTextureRenderer();
}
return;
}
try {
ContextManager.getCurrentContext().pushFBOTextureRenderer(this);
// Otherwise, we can streamline this by rendering to multiple textures at once.
// first determine how many groups we need
final LinkedList<Texture> depths = new LinkedList<Texture>();
final LinkedList<Texture> colors = new LinkedList<Texture>();
for (int i = 0; i < texs.size(); i++) {
final Texture tex = texs.get(i);
if (tex.getTextureStoreFormat().isDepthFormat()) {
depths.add(tex);
} else {
colors.add(tex);
}
}
// we can only render to 1 depth texture at a time, so # groups is at minimum == numDepth
final int groups = Math.max(depths.size(), (int) Math.ceil(colors.size() / (float) maxDrawBuffers));
final RenderContext context = ContextManager.getCurrentContext();
for (int i = 0; i < groups; i++) {
// First handle colors
int colorsAdded = 0;
while (colorsAdded < maxDrawBuffers && !colors.isEmpty()) {
final Texture tex = colors.removeFirst();
if (tex.getType() == Type.TwoDimensional) {
EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT + colorsAdded, GL11.GL_TEXTURE_2D,
tex.getTextureIdForContext(context.getGlContextRep()), 0);
} else if (tex.getType() == Type.CubeMap) {
EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT + colorsAdded,
LwjglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()),
tex.getTextureIdForContext(context.getGlContextRep()), 0);
} else {
throw new IllegalArgumentException("Invalid texture type: " + tex.getType());
}
colorsAdded++;
}
// Now take care of depth.
if (!depths.isEmpty()) {
final Texture tex = depths.removeFirst();
// Set up our depth texture
if (tex.getType() == Type.TwoDimensional) {
EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D,
tex.getTextureIdForContext(context.getGlContextRep()), 0);
} else if (tex.getType() == Type.CubeMap) {
EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT,
LwjglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()),
tex.getTextureIdForContext(context.getGlContextRep()), 0);
} else {
throw new IllegalArgumentException("Invalid texture type: " + tex.getType());
}
_usingDepthRB = false;
} else if (!_usingDepthRB) {
// setup our default depth render buffer if not already set
EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT,
_depthRBID);
_usingDepthRB = true;
}
setDrawBuffers(colorsAdded);
setReadBuffer(colorsAdded != 0 ? EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT : GL11.GL_NONE);
// Check FBO complete
checkFBOComplete(_fboID);
switchCameraIn(clear);
if (toDrawA != null) {
doDraw(toDrawA);
} else {
doDraw(toDrawB);
}
switchCameraOut();
}
// automatically generate mipmaps for our textures.
for (int x = 0, max = texs.size(); x < max; x++) {
if (texs.get(x).getMinificationFilter().usesMipMapLevels()) {
final Texture tex = texs.get(x);
if (tex.getMinificationFilter().usesMipMapLevels()) {
LwjglTextureStateUtil.doTextureBind(texs.get(x), 0, true);
EXTFramebufferObject.glGenerateMipmapEXT(LwjglTextureStateUtil.getGLType(tex.getType()));
}
}
}
} finally {
ContextManager.getCurrentContext().popFBOTextureRenderer();
}
}
@Override
protected void setupForSingleTexDraw(final Texture tex) {
final RenderContext context = ContextManager.getCurrentContext();
final int textureId = tex.getTextureIdForContext(context.getGlContextRep());
if (tex.getTextureStoreFormat().isDepthFormat()) {
// No color buffer
EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT, 0);
// Setup depth texture into FBO
if (tex.getType() == Type.TwoDimensional) {
EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, textureId, 0);
} else if (tex.getType() == Type.CubeMap) {
EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT,
LwjglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()), textureId,
0);
} else {
throw new IllegalArgumentException("Can not render to texture of type: " + tex.getType());
}
setDrawBuffer(GL11.GL_NONE);
setReadBuffer(GL11.GL_NONE);
} else {
// Set color texture into FBO
if (tex.getType() == Type.TwoDimensional) {
EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, GL11.GL_TEXTURE_2D, textureId, 0);
} else if (tex.getType() == Type.CubeMap) {
EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT,
LwjglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()), textureId,
0);
} else {
throw new IllegalArgumentException("Can not render to texture of type: " + tex.getType());
}
// setup depth RB
EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT, _depthRBID);
setDrawBuffer(EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT);
setReadBuffer(EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT);
}
// Check FBO complete
checkFBOComplete(_fboID);
}
private void setReadBuffer(final int attachVal) {
GL11.glReadBuffer(attachVal);
}
private void setDrawBuffer(final int attachVal) {
GL11.glDrawBuffer(attachVal);
}
private void setDrawBuffers(final int maxEntry) {
if (maxEntry <= 1) {
setDrawBuffer(maxEntry != 0 ? EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT : GL11.GL_NONE);
} else {
// We should only get to this point if we support ARBDrawBuffers.
_attachBuffer.clear();
_attachBuffer.limit(maxEntry);
ARBDrawBuffers.glDrawBuffersARB(_attachBuffer);
}
}
@Override
protected void takedownForSingleTexDraw(final Texture tex) {
// automatically generate mipmaps for our texture.
if (tex.getMinificationFilter().usesMipMapLevels()) {
LwjglTextureStateUtil.doTextureBind(tex, 0, true);
EXTFramebufferObject.glGenerateMipmapEXT(LwjglTextureStateUtil.getGLType(tex.getType()));
}
}
@Override
protected void setMSFBO() {
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferBlit.GL_DRAW_FRAMEBUFFER_EXT, _msfboID);
}
@Override
protected void blitMSFBO() {
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferBlit.GL_READ_FRAMEBUFFER_EXT, _msfboID);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferBlit.GL_DRAW_FRAMEBUFFER_EXT, _fboID);
EXTFramebufferBlit.glBlitFramebufferEXT(0, 0, _width, _height, 0, 0, _width, _height, GL11.GL_COLOR_BUFFER_BIT
| GL11.GL_DEPTH_BUFFER_BIT, GL11.GL_NEAREST);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferBlit.GL_READ_FRAMEBUFFER_EXT, 0);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferBlit.GL_DRAW_FRAMEBUFFER_EXT, 0);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
}
/**
* Check the currently bound FBO status for completeness. The passed in fboID is for informational purposes only.
*
* @param fboID
* an id to use for log messages, particularly if there are any issues.
*/
public static void checkFBOComplete(final int fboID) {
final int status = EXTFramebufferObject.glCheckFramebufferStatusEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT);
switch (status) {
case EXTFramebufferObject.GL_FRAMEBUFFER_COMPLETE_EXT:
break;
case EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
throw new IllegalStateException("FrameBuffer: " + fboID
+ ", has caused a GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT exception");
case EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
throw new IllegalStateException("FrameBuffer: " + fboID
+ ", has caused a GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT exception");
case EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
throw new IllegalStateException("FrameBuffer: " + fboID
+ ", has caused a GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT exception");
case EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
throw new IllegalStateException("FrameBuffer: " + fboID
+ ", has caused a GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT exception");
case EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
throw new IllegalStateException("FrameBuffer: " + fboID
+ ", has caused a GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT exception");
case EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
throw new IllegalStateException("FrameBuffer: " + fboID
+ ", has caused a GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT exception");
case EXTFramebufferObject.GL_FRAMEBUFFER_UNSUPPORTED_EXT:
throw new IllegalStateException("FrameBuffer: " + fboID
+ ", has caused a GL_FRAMEBUFFER_UNSUPPORTED_EXT exception.");
case EXTFramebufferMultisample.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
throw new IllegalStateException("FrameBuffer: " + fboID
+ ", has caused a GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT exception.");
default:
throw new IllegalStateException("Unexpected reply from glCheckFramebufferStatusEXT: " + status);
}
}
public void copyToTexture(final Texture tex, final int x, final int y, final int width, final int height,
final int xoffset, final int yoffset) {
LwjglTextureStateUtil.doTextureBind(tex, 0, true);
if (tex.getType() == Type.TwoDimensional) {
GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, xoffset, yoffset, x, y, width, height);
} else if (tex.getType() == Type.CubeMap) {
GL11.glCopyTexSubImage2D(
LwjglTextureStateUtil.getGLCubeMapFace(((TextureCubeMap) tex).getCurrentRTTFace()), 0, xoffset,
yoffset, x, y, width, height);
} else {
throw new IllegalArgumentException("Invalid texture type: " + tex.getType());
}
}
@Override
protected void clearBuffers(final int clear) {
GL11.glDisable(GL11.GL_SCISSOR_TEST);
_parentRenderer.clearBuffers(clear);
}
@Override
protected void activate() {
// Lazy init
if (_fboID == 0) {
final IntBuffer buffer = BufferUtils.createIntBuffer(1);
// Create our texture binding FBO
EXTFramebufferObject.glGenFramebuffersEXT(buffer); // generate id
_fboID = buffer.get(0);
// Create a depth renderbuffer to use for RTT use
EXTFramebufferObject.glGenRenderbuffersEXT(buffer); // generate id
_depthRBID = buffer.get(0);
EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, _depthRBID);
int format = GL11.GL_DEPTH_COMPONENT;
if (_supportsDepthTexture && _depthBits > 0) {
switch (_depthBits) {
case 16:
format = ARBDepthTexture.GL_DEPTH_COMPONENT16_ARB;
break;
case 24:
format = ARBDepthTexture.GL_DEPTH_COMPONENT24_ARB;
break;
case 32:
format = ARBDepthTexture.GL_DEPTH_COMPONENT32_ARB;
break;
default:
// stick with the "undefined" GL_DEPTH_COMPONENT
}
}
EXTFramebufferObject.glRenderbufferStorageEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, format, _width,
_height);
// unbind...
EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, 0);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
// If we support it, rustle up a multisample framebuffer + renderbuffers
if (_samples != 0 && _supportsMultisample) {
// create ms framebuffer object
EXTFramebufferObject.glGenFramebuffersEXT(buffer);
_msfboID = buffer.get(0);
// create ms renderbuffers
EXTFramebufferObject.glGenRenderbuffersEXT(buffer); // generate id
_mscolorRBID = buffer.get(0);
EXTFramebufferObject.glGenRenderbuffersEXT(buffer); // generate id
_msdepthRBID = buffer.get(0);
// set up renderbuffer properties
EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, _mscolorRBID);
EXTFramebufferMultisample.glRenderbufferStorageMultisampleEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT,
_samples, GL11.GL_RGBA, _width, _height);
EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, _msdepthRBID);
EXTFramebufferMultisample.glRenderbufferStorageMultisampleEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT,
_samples, format, _width, _height);
EXTFramebufferObject.glBindRenderbufferEXT(EXTFramebufferObject.GL_RENDERBUFFER_EXT, 0);
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, _msfboID);
EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT,
_mscolorRBID);
EXTFramebufferObject.glFramebufferRenderbufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, EXTFramebufferObject.GL_RENDERBUFFER_EXT,
_msdepthRBID);
// check for errors
checkFBOComplete(_msfboID);
// release
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
}
}
if (_active == 0) {
final RenderContext context = ContextManager.getCurrentContext();
final RendererRecord record = context.getRendererRecord();
// needed as FBOs do not share this flag it seems
record.setClippingTestValid(false);
// push a delimiter onto the clip stack
_neededClip = _parentRenderer.isClipTestEnabled();
if (_neededClip) {
_parentRenderer.pushEmptyClip();
}
GL11.glClearColor(_backgroundColor.getRed(), _backgroundColor.getGreen(), _backgroundColor.getBlue(),
_backgroundColor.getAlpha());
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, _fboID);
ContextManager.getCurrentContext().pushEnforcedStates();
ContextManager.getCurrentContext().clearEnforcedStates();
ContextManager.getCurrentContext().enforceStates(_enforcedStates);
}
_active++;
}
@Override
protected void deactivate() {
if (_active == 1) {
final ReadOnlyColorRGBA bgColor = _parentRenderer.getBackgroundColor();
GL11.glClearColor(bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(), bgColor.getAlpha());
EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, 0);
ContextManager.getCurrentContext().popEnforcedStates();
if (_neededClip) {
_parentRenderer.popClip();
}
}
_active--;
}
public void cleanup() {
if (_fboID != 0) {
final IntBuffer id = BufferUtils.createIntBuffer(1);
id.put(_fboID);
id.rewind();
EXTFramebufferObject.glDeleteFramebuffersEXT(id);
}
if (_depthRBID != 0) {
final IntBuffer id = BufferUtils.createIntBuffer(1);
id.put(_depthRBID);
id.rewind();
EXTFramebufferObject.glDeleteRenderbuffersEXT(id);
}
}
}