2

So I'm trying to make custom buttons, for which I need to combine different parts of the button background. To do this I figured using a FrameBuffer would work, however it did not give viable results. Therefore I attempted to test my FrameBuffer drawing method, by writing a simple test method, which returns a texture that is drawn to the display at every render() call. This method is here (note that it is a test method, so it may be a little poorly optimized):

    private Texture test()
{
    BitmapFont f = ReverseBlade.fontTitle;
    f.setColor(Color.LIGHT_GRAY);

    FrameBuffer fbo = new FrameBuffer(Format.RGBA8888, (int)f.getBounds("Hi").width, (int)f.getBounds("Hi").height, false);
    Batch b = ReverseBlade.batch;
    OrthographicCamera c = new OrthographicCamera(fbo.getWidth(), fbo.getHeight());

    c.setToOrtho(false);
    c.update();
    b.setProjectionMatrix(c.combined);

    fbo.begin();
    b.begin();

    f.draw(b, "Hi", 0, 0);

    b.end();
    fbo.end();

    Texture t = fbo.getColorBufferTexture();

    fbo.dispose();

    b.setProjectionMatrix(ReverseBlade.camera.combined);

    return t;
}

However, nothing is displayed. The screen is dark... I have tried without the camera and multiple other variations that I can no longer remember. What am I doing wrong?

Half Solution What I ended up having to do is to make a new Matrix4 object for the FrameBuffer like this:

Matrix4 m = new Matrix4();
m.setToOrtho2D(0, 0, fbo.getWidth(), fbo.getHeight());
batch.setProjectionMatrix(m);

However, this makes everything that is drawn be upside down, like this: Upside Down

Daahrien
  • 10,190
  • 6
  • 39
  • 71
StrongJoshua
  • 975
  • 10
  • 24

5 Answers5

3

I think the fbo.dispose() call is destroying more than you want.

See the source and notice where it destroys the colorTexture, which is the result of getColorBufferTexture().

I think this could be considered a bug in Libgdx. The color texture is generally something that should have a very different lifetime than the FBO, so cleaning up the texture seems a bit too aggressive. However, trying to figure out which cases to clean the texture up is probably complicated.....

P.T.
  • 24,557
  • 7
  • 64
  • 95
  • That's probably the reason. But I'm not sure it can be considered a bug or too aggressive cleaning of resources. The texture and the FBO should have the same lifetime imho. I'm not sure about the OpenGL internals here, but when disposing the FBO, is it even possible to still access the "texture" it was rendering to? – noone Jun 03 '14 at 09:00
  • So I commented out the dispose call and set the draw Y coordinate for the text to fbo.getHeight() and I manage to see a tiny sliver of bright pixels (with the Y at 0 I see nothing). – StrongJoshua Jun 03 '14 at 09:02
1

So following what I added with the Half Solution, all I had to do was create a new Sprite object with the texture from the FBo and call flip(false, true)!

StrongJoshua
  • 975
  • 10
  • 24
1

May be this is a workaround to dispose() the framebuffer and keeping the texture alive. I do the following:

public class TextureSaveFBO extends FrameBuffer {
    static final Texture DUMMY = new Texture(1, 1, Format.RGB565) {
        public void dispose() {
        };
    };

    public TextureSaveFBO(Format format, int width, int height,
            boolean hasDepth) {
        super(format, width, height, hasDepth);
    }

    @Override
    public void dispose() {
        // prevents the real texture of dispose()
        Texture t = colorTexture;
        colorTexture = DUMMY;
        super.dispose();
        colorTexture = t;
    }
}
  • Didn't think I would need this, but after re-assessing how my project was going to be organized, I realized I definitely would! Thanks for letting me know :) – StrongJoshua Jun 15 '14 at 09:24
1

Just a precisation:

OrthographicCamera c = new OrthographicCamera(fbo.getWidth(), fbo.getHeight());
c.setToOrtho(false);

This is potentially harmful unless you know what you are doing: c.setOrtho(false) does the following:

Sets this camera to an orthographic projection using a viewport fitting the screen resolution, centered at (Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2), with the y-axis pointing up or down.

So even if you specified in the OrthographicCamera's constructor that you want the viewport to be of the frame buffer size, you are overwriting that with the following call to a viewport covering the screen size and centered to the screen center.

You should probably do:

camera.setToOrtho(false, fbo.getWidth(), fbo.getHeight());
Lake
  • 4,072
  • 26
  • 36
  • Wow, I didn't even notice that. Thanks for bringing that to my attention :) I have given up the use of `FrameBufferObjects` in favor of more convenient methods, but this is really good to know as a future reference! – StrongJoshua Jul 16 '14 at 09:57
0

Issue solved since LibGDX 1.6.5.

It's now possible to override disposeColorBuffer method to not dispose rendered texture.

mgsx-dev
  • 440
  • 3
  • 5