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 GL gl = GLContext.getCurrentGL();
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 {
doDraw(toDrawB);
}
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) {
gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0 + colorsAdded,
GL.GL_TEXTURE_2D, tex.getTextureIdForContext(context.getGlContextRep()), 0);
} else if (tex.getType() == Type.CubeMap) {
gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0 + colorsAdded,
JoglTextureStateUtil.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) {
gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_TEXTURE_2D,
tex.getTextureIdForContext(context.getGlContextRep()), 0);
} else if (tex.getType() == Type.CubeMap) {
gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT,
JoglTextureStateUtil.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
gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER,
_depthRBID);
_usingDepthRB = true;
}
setDrawBuffers(colorsAdded);
setReadBuffer(colorsAdded != 0 ? GL.GL_COLOR_ATTACHMENT0 : GL.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++) {
final Texture tex = texs.get(x);
if (tex.getMinificationFilter().usesMipMapLevels()) {
JoglTextureStateUtil.doTextureBind(tex, 0, true);
gl.glGenerateMipmap(JoglTextureStateUtil.getGLType(tex.getType()));
}
}
} finally {
ContextManager.getCurrentContext().popFBOTextureRenderer();
}