/*
This file is part of jpcsp.
Jpcsp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jpcsp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jpcsp. If not, see <http://www.gnu.org/licenses/>.
*/
package jpcsp.graphics.textures;
import jpcsp.graphics.GeCommands;
import jpcsp.graphics.VideoEngine;
import jpcsp.graphics.RE.IRenderingEngine;
/**
* A texture being used as a render target, using OpenGL FrameBuffer Object (FBO).
*
* @author gid15
*
*/
public class FBTexture extends GETexture {
private int fboId = -1;
private int depthRenderBufferId = -1;
public FBTexture(int address, int bufferWidth, int width, int height, int pixelFormat) {
super(address, bufferWidth, width, height, pixelFormat, true);
}
public FBTexture(FBTexture copy) {
super(copy.address, copy.bufferWidth, copy.width, copy.height, copy.pixelFormat, copy.useViewportResize);
}
@Override
public void bind(IRenderingEngine re, boolean forDrawing) {
if (forDrawing) {
// We are copying the texture back to the main frame buffer,
// bind the texture, not the FBO.
re.bindFramebuffer(IRenderingEngine.RE_FRAMEBUFFER, 0);
super.bind(re, forDrawing);
} else {
if (fboId == -1) {
createFBO(re, forDrawing);
} else {
// Bind the FBO
re.bindFramebuffer(IRenderingEngine.RE_FRAMEBUFFER, fboId);
}
}
}
protected void createFBO(IRenderingEngine re, boolean forDrawing) {
// Create the FBO and associate it to the texture
fboId = re.genFramebuffer();
re.bindFramebuffer(IRenderingEngine.RE_FRAMEBUFFER, fboId);
// Create a render buffer for the depth buffer
depthRenderBufferId = re.genRenderbuffer();
re.bindRenderbuffer(depthRenderBufferId);
re.setRenderbufferStorage(IRenderingEngine.RE_DEPTH_COMPONENT, getTexImageWidth(), getTexImageHeight());
// Create the texture
super.bind(re, forDrawing);
// Attach the texture to the FBO
re.setFramebufferTexture(IRenderingEngine.RE_FRAMEBUFFER, IRenderingEngine.RE_COLOR_ATTACHMENT0, textureId, 0);
// Attach the depth buffer to the FBO
re.setFramebufferRenderbuffer(IRenderingEngine.RE_FRAMEBUFFER, IRenderingEngine.RE_DEPTH_ATTACHMENT, depthRenderBufferId);
}
@Override
public void delete(IRenderingEngine re) {
if (fboId != -1) {
re.deleteFramebuffer(fboId);
fboId = -1;
}
if (depthRenderBufferId != -1) {
re.deleteRenderbuffer(depthRenderBufferId);
depthRenderBufferId = -1;
}
super.delete(re);
}
public void blitFrom(IRenderingEngine re, FBTexture src) {
if (fboId == -1) {
createFBO(re, false);
}
// Bind the source and destination FBOs
re.bindFramebuffer(IRenderingEngine.RE_READ_FRAMEBUFFER, src.fboId);
re.bindFramebuffer(IRenderingEngine.RE_DRAW_FRAMEBUFFER, fboId);
// Copy the source FBO to the destination FBO
re.blitFramebuffer(0, 0, src.getResizedWidth(), src.getResizedHeight(), 0, 0, getResizedWidth(), getResizedHeight(), IRenderingEngine.RE_COLOR_BUFFER_BIT, GeCommands.TFLT_NEAREST);
// Re-bind the source FBO
re.bindFramebuffer(IRenderingEngine.RE_FRAMEBUFFER, src.fboId);
}
@Override
public String toString() {
return String.format("FBTexture[0x%08X-0x%08X, %dx%d, bufferWidth=%d, pixelFormat=%d(%s)]", address, address + length, width, height, bufferWidth, pixelFormat, VideoEngine.getPsmName(pixelFormat));
}
}