-1

I'm working on a word game and I was dynamically creating the textures for the letter tiles when the game loads, comprising of a background image and a font.

To do this I was drawing pixmaps onto pixmaps, this was all fine until I started working on scaling. The font scaling on the pixmaps was terrible, even with bilinear filtering turned on (left image below) even though my scaled fonts were looking pretty good elsewhere.

So I decided to get round this I'd use a frame buffer, render everything to that and then copy that out to a pixmap and create a texture from that. That way I could use the gpu filtering and it should look exactly the same as my other fonts, (middle image below) but it still didn't look quite as nice as the other fonts. A slight dark line round the outside, it looks like the alpha blending isn't working properly.

I then tried drawing straight over the tiles with the font at runtime to make sure it wasn't my imagination, and this definitely looks better with smooth blending into the image below (right image below), but this impacts my frame rate quite a lot.

examples

So my question is, why is drawing to the frame buffer not producing the same result as when I draw to the screen? Code below.

    Texture tx = Assets.loadTexture("bubbles/BubbleBlue.png");
    tx.setFilter(TextureFilter.Linear, TextureFilter.Linear);
    SpriteBatch sb = new SpriteBatch();
    FrameBuffer fb = new FrameBuffer(Format.RGBA8888,
            LayoutManager.getWidth(), LayoutManager.getHeight(), false);
    fb.begin();
    sb.begin();
    sb.draw(tx, 0, 0, LetterGrid.blockWidth, LetterGrid.blockHeight);

    Assets.candara80.font.getRegion().getTexture()
            .setFilter(TextureFilter.Linear, TextureFilter.Linear);
    Assets.candara80.setSize(0.15f);

    TextBounds textBounds = Assets.candara80.getBounds(letter);

    Assets.candara80.drawText(sb, letter,
            (LetterGrid.blockWidth - textBounds.width) / 2,
            (LetterGrid.blockHeight + textBounds.height) / 2);

    sb.end();

    Pixmap pm = ScreenUtils.getFrameBufferPixmap(0, 0,
            (int) LetterGrid.blockWidth, (int) LetterGrid.blockHeight);
    Pixmap flipped = flipPixmap(pm);

    result = new Texture(flipped);

    fb.end();
    pm.dispose();
    flipped.dispose();
    tx.dispose();
    fb.dispose();
    sb.dispose();
Will Calderwood
  • 4,393
  • 3
  • 39
  • 64
  • Try to set the FrameBuffer size the same size as the screen (`gdx.graphics.getWidth/Height()`). This sets the FBO size to the same size as the window/the screen, so you can be sure that the size does not affect the result. But i don't know much about FBOs so just an idea, not sure if it helps – Robert P Mar 13 '14 at 16:48
  • @Springrbua Thanks, buy my LayoutManager width and height are the same as the screen size, so that's not the issue. – Will Calderwood Mar 13 '14 at 16:59
  • Is it just me or is the font in the first image not the same size? I mean if even if they are examples of various sizes the first image looks bigger in relation to the background.... You say dynamically creating but does that include using FreeTypeFontGenerator? If super pretty text is your goal then why not generate the font bitmaps at the needed size instead of trying to scale them? – Chase Mar 13 '14 at 19:20
  • @Chase They are the same font and same scaling. Position is slightly different as it was positioned with the glyph data rather than the text bounds. I found the FreeTypeFontGenerator didn't generate very smooth fonts, the edges aren't soft enough and therefore they don't blend well + there were some glitches in them. A slightly blurry font produces nicer looking results, even with no scaling. I also played with Distance Field fonts but they don't scale down well. Amazing at scaling up though, but not from a small size. – Will Calderwood Mar 13 '14 at 19:26
  • You cannot safely use Format.RGBA8888 for the FrameBuffer when targeting Android, because many devices do not support it. See the Javadocs for the FrameBuffer. I don't know why you're getting different results on the FrameBuffer, but it looks just like a case where pre-multiplied alpha would fix it. – Tenfour04 Mar 13 '14 at 21:11
  • @Tenfour04 Thanks for the tip about the frame buffer. I'll take a look at the premultiplied alpha issue tomorrow. – Will Calderwood Mar 13 '14 at 23:49

1 Answers1

0

set PROJECTION is the problem.

EXAMPLE

        public Texture texture(Color fg_color, Color bg_color)
        {
            Pixmap pm = render( fg_color, bg_color );
            texture = new Texture(pm);//***here's your new dynamic texture***
            disposables.add(texture);//store the texture
        }
    //---------------------------
        public Pixmap render(Color fg_color, Color bg_color)
        {
            int width = Gdx.graphics.getWidth();
            int height = Gdx.graphics.getHeight();

            SpriteBatch spriteBatch = new SpriteBatch();

            m_fbo = new FrameBuffer(Format.RGB565, (int)(width * m_fboScaler), (int)(height * m_fboScaler), false);
            m_fbo.begin();
            Gdx.gl.glClearColor(bg_color.r, bg_color.g, bg_color.b, bg_color.a);
            Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
/**set PROJECTION**/
            Matrix4 normalProjection = new Matrix4().setToOrtho2D(0, 0, Gdx.graphics.getWidth(),  Gdx.graphics.getHeight());
            spriteBatch.setProjectionMatrix(normalProjection);

            spriteBatch.begin();
            spriteBatch.setColor(fg_color);
            //do some drawing ***here's where you draw your dynamic texture***
            ...
            spriteBatch.end();//finish write to buffer

            pm = ScreenUtils.getFrameBufferPixmap(0, 0, (int) width, (int) height);//write frame buffer to Pixmap

            m_fbo.end();
    //      pm.dispose();
    //      flipped.dispose();
    //      tx.dispose();
            m_fbo.dispose();
            m_fbo = null;
            spriteBatch.dispose();
    //      return texture;
            return pm;
        }
Jon Goodwin
  • 9,053
  • 5
  • 35
  • 54