3

I am writting simple "Hello World"-style program , that writes current nameday on screen. I want to ensure , that text would be readable and correct drawn also after resizing the window.

In my create method, I tried to use this code (according this article: https://github.com/libgdx/libgdx/wiki/Viewports)

public void create () {

        //if(_isLandscape)
        //    Gdx.graphics.setDisplayMode(1920, 1080, false);

        if(_isLandscape)
            Gdx.graphics.setDisplayMode(960, 540, false);

        camera = new PerspectiveCamera();
        //viewport = new FillViewport(960, 540, camera); - I have also tried to use this
        viewport = new ScreenViewport(camera);
....

In resize(int, int) method, I have this code:

public void resize(int width , int height){
        try {
           viewport.update(width, height);
            System.out.println(width + " " + height);
            if (height > width) {
                _isLandscape = false;
                System.out.println("Portrait");
            } else {
                _isLandscape = true;
                System.out.println("Landscape");
            }
        }catch(Exception ex){
        }
    }

But the result is still streched or unreadable texts after resizing. Streched texts

Minimized texts

Please, I would like to achieve, that texts would be scaled in way, that if window would be small, texts would be still same but some parts will be "behind" border. If window would be large (eg. full screen) texts would be on same position not streched.

Here is my full code that I have now:

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.viewport.*;

import com.badlogic.gdx.graphics.OrthographicCamera;

import java.io.File;
import java.util.List;

//import com.badlogic.gdx.tools.imagepacker.TexturePacker2;
//import com.badlogic.gdx.tools.texturepacker.TexturePacker;

/**
 * Created by Martin on 30.9.2014.
 */
public class NameDayExampleApp extends HostedGame{
    private Viewport viewport;
    private Camera camera;
    private OrthographicCamera _ortocamera;

    private SpriteBatch _spriteBatch;
    private Texture background;
    private Texture backgroundLandscape;
    private boolean _isLandscape;

    private String name = "";

    private TextureAtlas textureAtlas;

    private static final String TAG = "NameDayExampleApp";
    private static final int VERSION = 1;
    private static final int FONT_SIZE = 30;
    private static final float CLEAR_COLOR = 0.1f;

    private static final int MAX_FONT_SIZE = 40;
    private static final int MIN_FONT_SIZE = 8;

    private IServiceProvider _serviceProvider;
    private ILog _log;
    private BitmapFont _font;
    String _language;

    private int currentFontSize;

    private int currentHeight;
    private int currentWidth;

    boolean isDebugged = true;

    @Override
    public void initialize(IServiceProvider serviceProvider, List<SocialFeedDefinition> feeds, boolean isLandscape, String language)
    {
        _serviceProvider = serviceProvider;
        _log = serviceProvider.getLog().getSubLog(TAG);


        _isLandscape = isLandscape;
        _language = language;

        _serviceProvider.getAppStatusListener().onStateChanged(AppState.Ready);

    }

    @Override
    public void create () {

        _serviceProvider.getLog().log(LogLevel.Info, "[NameDay]: Start creating screen");


        if(_isLandscape)
            Gdx.graphics.setDisplayMode(Gdx.graphics.getHeight(), Gdx.graphics.getWidth(), false);//Gdx.graphics.setDisplayMode(960, 540, false);

        currentHeight = Gdx.graphics.getHeight();
        currentWidth  = Gdx.graphics.getWidth();


       // _ortocamera = new OrthographicCamera(currentWidth, currentHeight);
        //viewport = new ExtendViewport(currentWidth, currentHeight, _ortocamera);
        viewport = new StretchViewport(currentWidth, currentHeight);
        currentFontSize = FONT_SIZE;

        try
        {
            _spriteBatch = new SpriteBatch();


            background = new Texture(_serviceProvider.getAssetHandleResolver().resolve("nameday-portrait.jpg").file().getName());
            backgroundLandscape = new Texture(_serviceProvider.getAssetHandleResolver().resolve("nameday-landscape.jpg").file().getName());

            //FreeTypeFontGenerator generator = new FreeTypeFontGenerator(new FileHandle("fonts/DroidSans_Bold.ttf"));
            // _serviceProvider.getFontGenerator().generateExistenceFont(20,  FontType.NORMAL);

            _font = _serviceProvider.getFontGenerator().generateDefaultFont(currentFontSize,  FontType.NORMAL); //generator.generateFont(40);
            _font.setColor(0,0,0,1);
            //generator.dispose();
        }
        catch(GdxRuntimeException e)
        {
            _log.error("Exception on create: " + e);
            _serviceProvider.getAppStatusListener().onStateChanged(AppState.Error);
        }
    }

    @Override
    public void render () {

        try
        {

            Gdx.gl.glClearColor(1, 0, 0, 1);
            Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

            //background draw
            if(isDebugged) {
                _log.log(LogLevel.Info, "currentWidth: " + currentWidth + " currentHeight: " + currentHeight);
                _log.log(LogLevel.Info, "Window width: " + Gdx.graphics.getWidth() + " Window height: " + Gdx.graphics.getHeight());
                _log.log(LogLevel.Info, "Background width: " + background.getWidth() + " Background height: " + background.getHeight());
                isDebugged = false;
            }


            if(!_isLandscape) {
                _spriteBatch.begin();
                //_spriteBatch.draw(background, 0, 0, currentWidth, currentHeight);
                _spriteBatch.draw(background,0,0);
                _spriteBatch.end();
            }else{
                _spriteBatch.begin();
                //_spriteBatch.draw(backgroundLandscape, 0, 0, currentWidth, currentHeight);
                _spriteBatch.draw(backgroundLandscape, 0, 0);
                _spriteBatch.end();
            }


            //content draw
            _spriteBatch.begin();

            NameDaySAX nameDaySAX = new NameDaySAX();

            //Choose XML according to language
            FileHandle _fileHandle = null;
            File _file = null;
            _fileHandle = _serviceProvider.getAssetHandleResolver().resolve("namesday_" + _language + ".xml");
            _file = _fileHandle.file();
            if(_file.exists()){
              name = nameDaySAX.getCurrentName(_file);
            }else {
                _fileHandle = _serviceProvider.getAssetHandleResolver().resolve("namesday.xml");
                _file = _fileHandle.file();
                name = nameDaySAX.getCurrentName(_file);
            }

            if(!_isLandscape) {
                BitmapFont.TextBounds bounds = _font.getBounds(_serviceProvider.getLocalizer().get("Today celebrates"));//_font.getBounds("Happy Name Day");
                _font.draw(_spriteBatch, _serviceProvider.getLocalizer().get("Today celebrates"), (Gdx.graphics.getWidth()-bounds.width) / 6.0f, Gdx.graphics.getHeight() - 35);
                bounds = _font.getBounds(_serviceProvider.getLocalizer().get("nameday") + " " + name);
                _font.draw(_spriteBatch, _serviceProvider.getLocalizer().get("nameday") + " " + name, (Gdx.graphics.getWidth()-bounds.width) / 5.0f, Gdx.graphics.getHeight() - 70);
            }else{
                BitmapFont.TextBounds bounds = _font.getBounds(_serviceProvider.getLocalizer().get("Happy Name Day"));
                _font.draw(_spriteBatch, _serviceProvider.getLocalizer().get("Today celebrates"), (Gdx.graphics.getWidth()-bounds.width) / 14.0f, Gdx.graphics.getHeight() / 1.7f);
                bounds = _font.getBounds(_serviceProvider.getLocalizer().get("nameday") + " " + name);
                _font.draw(_spriteBatch, _serviceProvider.getLocalizer().get("nameday") + " " + name, (Gdx.graphics.getWidth()-bounds.width) / 11.0f, Gdx.graphics.getHeight() / 2.0f);
            }
        }
        catch(RuntimeException e)
        {
            _log.error("Exception on render: " + e);
            _serviceProvider.getAppStatusListener().onStateChanged(AppState.Error);
        }
        finally {
            _spriteBatch.end();
        }
    }

    @Override
    public void resize(int width , int height){
        try {

            viewport.update(width, height);
            //_ortocamera.update();
            isDebugged = true;
            //Set Landscape flag
            if (height > width) {
                _isLandscape = false;
                _log.log(LogLevel.Info, "Portrait");
            } else {
                _isLandscape = true;
                _log.log(LogLevel.Info, "Landscape");
            }

            float scale = 1.0f, scale1, scale2;
            scale1 = (width * 1.0f) / (currentWidth * 1.0f);
            scale2 = (height * 1.0f) / (currentHeight * 1.0f);

            if(currentWidth<width || currentHeight<height){
                if(scale1>scale2){
                    scale = scale1;
                }else{
                    scale = scale2;
                }
            }

            if(currentWidth>width || currentHeight>height){
                if(scale1<scale2){
                    scale = scale1;
                }else{
                    scale = scale2;
                }
            }

            if(scale<0.9)
                scale=0.9f;
            if(scale>1.2){
                scale=1.2f;
            }

            //Font Scaling
            /*if(!_isLandscape) {
                scale = (width * 1.0f) / (currentWidth * 1.0f);
            }else {
                scale = (height * 1.0f) / (currentHeight * 1.0f);
            }*/

            currentWidth = width;
            currentHeight = height;

            _log.log(LogLevel.Info, "New width: " + width + " New height: " + height);
            _log.log(LogLevel.Info, "Scale: " + scale);

            float fontsize = currentFontSize;
            float fcurrentFontSize;
            _font.dispose();
            fcurrentFontSize = fontsize * scale;

            if(fcurrentFontSize > MAX_FONT_SIZE)
                fcurrentFontSize = MAX_FONT_SIZE;
            if(fcurrentFontSize < MIN_FONT_SIZE)
                fcurrentFontSize = MIN_FONT_SIZE;

            currentFontSize = (int)fcurrentFontSize;
            _font = _serviceProvider.getFontGenerator().generateDefaultFont(currentFontSize,  FontType.NORMAL);
            _font.setColor(0,0,0,1);

            _log.info("Fontsize: " + currentFontSize);
            _log.info(width + "x" + height);
            //End of font scaling


        }catch(Exception e){
            _log.error("Exception on resize: " + e);
            _serviceProvider.getAppStatusListener().onStateChanged(AppState.Error);
        }
    }

    public int getVersion()
    {
        return VERSION;
    }

    @Override
    public void dispose()
    {
        super.dispose();
        _font.dispose();
        background.dispose();
        backgroundLandscape.dispose();
    }
}
  • You should probably be using an OrthographicCamera instead of a PerspectiveCamera for the text. If you need the background to be in 3D, you can have two separate cameras, and only use the ortho camera for the text. – Tenfour04 Oct 13 '14 at 12:47
  • Please do you have some example code, how to setup OrthographicCamera? – Martin Fedy Fedorko Oct 14 '14 at 15:18
  • Use the Viewport class to handle your OrthographicCamera. Read the documentation here to decide which type of Viewport works for your purpose. https://github.com/libgdx/libgdx/wiki/Viewports – Tenfour04 Oct 14 '14 at 16:28
  • I still a little bit lost, because I've tried all Viewports and after resizing of screen, the font was still deformed. – Martin Fedy Fedorko Oct 23 '14 at 14:35
  • My code: @Override public void create () { _serviceProvider.getLog().log(LogLevel.Info, "[NameDay]: Start creating screen"); if(_isLandscape) Gdx.graphics.setDisplayMode(960, 540, false); OrthographicCamera(viewport.getScreenWidth(), viewport.getScreenHeight()); _ortocamera = new OrthographicCamera(960, 540); viewport = new FitViewport(960, 540, _ortocamera); – Martin Fedy Fedorko Oct 23 '14 at 14:48
  • Once you instantiate a Viewport class for your camera, you should never directly change the width and height of the camera again. Just use the `viewport.update` method in your `resize` method. The Viewport class manages camera size changes. I recommend using FitViewport, with a starting width and height that you know is big enough to encompass all your text. But you never showed your code for drawing the text. Maybe the problem is there. – Tenfour04 Oct 23 '14 at 15:54
  • Please , I 've added full code to my post. Can you look at it? I've tried to make some algorithm to make fonts smaller but it is not very good solution. So probably you can ignore this part. Important is just what to do with viewports and text draw. Thank you very much – Martin Fedy Fedorko Oct 30 '14 at 14:37
  • @Tenfour04 I would be very thankful, if you can help me. Thanks! – Martin Fedy Fedorko Oct 30 '14 at 14:42
  • You need to call `_spriteBatch.setProjectionMatrix(viewport.getCamera().combined);` in your render method before calling `_spriteBatch.begin` the first time. – Tenfour04 Oct 30 '14 at 15:26
  • It makes red screen with moved drawable area. Viewport should be initialized in this way? viewport = new FitViewport(currentWidth, currentHeight); when currentHeight = Gdx.graphics.getHeight(); and currentWidth = Gdx.graphics.getWidth(); – Martin Fedy Fedorko Oct 30 '14 at 16:22
  • You need to read the javadocs for whichever Viewport subclass you are using...I'm not sure which because your code above has StretchViewport but now you are saying FitViewport. But most Viewports take the desired *virtual* width and height as arguments in their constructors, not the current screen width and height. – Tenfour04 Oct 30 '14 at 17:57

1 Answers1

1

You should try to use also the FreeType extension by Libgdx...

If you want to draw text in your game, you usually use a BitmapFont. However, there is a downside: BitmapFonts rely on an image, so you have to scale them if you want a different size, which may look ugly.

You could just save a BitmapFont of the biggest size needed in your game then and you never have to scale up, just down, right? Well, that's true, but such a BitmapFont can easily take up two times as much space on your hard drive as the corresponding TrueType Font (.ttf). Now imagine you have to ship all your big BitmapFonts with your game and your game uses ten different fonts... on an Android device.

The solution to your problem is the gdx-freetype extension:

  • ship only lightweight .ttf files with your game
  • generate a BitmapFont of your desired size on the fly
  • user might put his own fonts into your game

quoted by: https://github.com/libgdx/libgdx/wiki/Gdx-freetype

Community
  • 1
  • 1
snailer
  • 62
  • 6