Skip to content

Instantly share code, notes, and snippets.

@eigenbom
Created December 8, 2015 21:48
Show Gist options
  • Save eigenbom/fcfa329b5073d85aa63c to your computer and use it in GitHub Desktop.
Save eigenbom/fcfa329b5073d85aa63c to your computer and use it in GitHub Desktop.
A single-context Framebuffer render target for SFML
// NB: Requires some changes to the SFML headers to make some parts public
////////////// HEADER
// A single-context Framebuffer render target
// A lighter version of sf::RenderTexture
// NB: MUST call SetContextOwner before create()
class FBOTargetImpl : public sf::RenderTarget {
public:
FBOTargetImpl();
virtual ~FBOTargetImpl();
// Set the context for FBOs to be created on
// Must call this before any create(...) calls will work
static void SetContextOwner(sf::RenderWindow* window);
// Create the FBOTarget
bool create(unsigned int w, unsigned int h);
bool setActive(bool active = true);
void display();
virtual sf::Vector2u getSize() const;
const sf::Texture& getTexture() const;
void setSmooth(bool smooth);
private:
virtual bool activate(bool active);
// Shared context
static sf::RenderWindow* sContextOwner;
// Internals
unsigned int mFbo; // FBO id
sf::Texture mTexture; // Target texture to draw on
unsigned int mTex;
};
///////////////////// SOURCE
sf::RenderWindow* FBOTargetImpl::sContextOwner = nullptr;
FBOTargetImpl::FBOTargetImpl() :mFbo(0), mTex(0){
}
FBOTargetImpl::~FBOTargetImpl(){
// cleanup (will auto kill the texture, but need to delete the fbo)
if (mFbo != 0){
glDeleteFramebuffers(1, &mFbo);
}
}
// Set the context for FBOs to be created on
// Must call this before any create(...) calls will work
void FBOTargetImpl::SetContextOwner(sf::RenderWindow* window){
sContextOwner = window;
}
// Create the FBOTarget
bool FBOTargetImpl::create(unsigned int w, unsigned int h){
if (sContextOwner == nullptr) return false;
// TODO: Fallback to sf::RenderTexture if we can't make FBOs
// Create the objects using the shared context
sContextOwner->setActive(true);
if (!mTexture.create(w, h)){
LOG_WARN() << "Couldn't create texture";
return false;
}
mTexture.setSmooth(false);
mTexture.m_fboAttachment = true;
// get texture id
mTex = mTexture.getNativeHandle();
/*GLint tex;
sf::Texture::bind(&mTexture);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex);
if (tex >= 0) mTex = tex;
*/
// make fbo
glGenFramebuffers(1, &mFbo);
glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
//Attach 2D texture to this FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTex, 0);
//Does the GPU support current FBO configuration?
GLenum status;
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE){
// Badness
LOG_WARN() << "Couldn't create fbo";
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return false;
}
// Finally, intialize the parent
RenderTarget::initialize();
return true;
}
bool FBOTargetImpl::setActive(bool active){
bool res = sContextOwner->setActive(true);
if (active){
GLint currentFbo;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &currentFbo);
if (currentFbo != mFbo){
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTex, 0);
}
}
else {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
return true;
}
void FBOTargetImpl::display(){
if (setActive(true)){
glFlush();
mTexture.m_pixelsFlipped = true;
}
}
sf::Vector2u FBOTargetImpl::getSize() const {
// NB: getSize() is called in initialise to setup the default viewport
return mTexture.getSize();
};
const sf::Texture& FBOTargetImpl::getTexture() const {
return mTexture;
}
bool FBOTargetImpl::activate(bool active){
return setActive(active);
}
void FBOTargetImpl::setSmooth(bool smooth){
mTexture.setSmooth(smooth);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment