I’m trying to create a simple drawing app with an FBO.
resetFbo() is supposed to fill the FBO with green.
When mouse is down, a circle brush is supposed to draw into FBO.
When I draw, the green background disappears (becomes black), the brush strokes stay.
Can anyone tell me what I’m doing wrong?
Thanks for your help
Here’s a couple of changes that will fix the problem you’re seeing. The main problem you had was that you weren’t being mindful of OpenGL being one big state machine. Your call to gl::color to draw the red circle persists until another call is made to override it, which meant you were blitting that FBO to the screen modulated with red.
For this reason, cinder has a whole bunch of gl::Scoped* structs that automatically save and restore the affected state using RAII to try and minimize this issue. Here’s the code i’ve changed to make it work, along with a few short annotations to help you along. Hope this makes sense.
void DrawingCanvasApp::update()
{
if ( mMousePressed ) // Don't bother binding the fbo if we're not going to draw anything
{
gl::ScopedMatrices matrices; // Automatically restore the current matrices when we exit this scope
gl::setMatricesWindow( mFBO->getSize() );
gl::ScopedViewport vp( ivec2 ( 0 ), mFBO->getSize() ); // Automatically restore the current viewport when we exit this scope
gl::ScopedFramebuffer buffer { mFBO }; // Automatically unbind the framebuffer when we exit this scope.
gl::ScopedBlendAlpha blend;
{
gl::ScopedColor color ( ColorA( 1, 0, 0, 1 ) ); // Automatically restore the color when we exit this scope. Seeing a pattern here? ;)
gl::drawSolidCircle( mMouse, 25.0f, 32 );
}
}
}
void DrawingCanvasApp::draw()
{
// There's a few places in here where some gl::Scoped* calls would be good hygiene, but i'll leave that up to you.
gl::clear( Color( 0.0, 0.0, 1.0 ) );
gl::enableAlphaBlending();
gl::setMatricesWindow( getWindowSize() );
gl::viewport( getWindowSize() );
gl::draw( mFBO->getColorTexture() );
}
void DrawingCanvasApp::resetFbo()
{
gl::setMatricesWindow( mFBO->getSize() );
gl::viewport( mFBO->getSize() );
gl::ScopedFramebuffer buffer { mFBO };
gl::clear ( ColorA( 0, 1, 0, 1 ) );
}
Hi @lithium, back again!
I’m trying to add an elaboration to my code - using nanovg to render…
With your corrections, this code seems to work properly with the standard cinder calls, but not with the nanovg versions shown below.
As I understand it, “nvgBeginFrame() defines the size of the window to render to in relation currently set viewport (i.e. glViewport on GL backends)”
But for whatever reason, I have some sort of viewport issue.
Any thoughts? Thanks again!
This seems like a problem with nanovg itself. i know it pokes at a bit of gl state (which is mentioned in the docs) but i don’t think it cleans up perfectly. For example it leaves a different vao bound, which confuses cinder’s internal state (call gl::context()->sanityCheck() to see what the problems are)
It’s likely not a viewport issue at all, but an errant depth mode, stencil state, or something like that. Fire up your favourite OpenGL debugger and have a look at the GL state before and after nanovg gets involved and hopefully something will jump out at you.