skymedium
skymedium

Reputation: 807

How to scale down Texture in libgdx to fit smaller screens?

My app provides two buttons in a table row. Each image has a width of 300 pixel (source). The app shows all parts of both buttons if I provide an initial window width which is greater than 600. Even resizing the window to a smaller size works smoothly. Both buttons are shown fully and they get scaled down if needed when resizing the window. The buttons are cut off once I provide an initial window size which is smaller than 600 pixel. How can I show the whole buttons on small screens by default?

Screenshots:

enter image description here

My code looks like this:

public class LevelChooserState extends GameState {

private Stage stage;
private Texture bgTexture;
private Pixmap bgPixmap;
private Viewport viewportStage;
private Container<Table> container;
private Table table;

public LevelChooserState(final GameStateController gsc) {
    super(gsc);

    Gdx.app.log(TAG, "Setup Level Chooser State.");

    // Setup Background Color
    bgPixmap = new Pixmap(1, 1, Pixmap.Format.RGB565);
    bgPixmap.setColor(Color.WHITE);
    bgPixmap.fill();
    bgTexture = new Texture(bgPixmap);
    TextureRegionDrawable textureRegionDrawableBg = new TextureRegionDrawable(new TextureRegion(bgTexture));

    // Setup viewports
    viewportStage = new ExtendViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    viewportStage.setScreenBounds(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

    // Setup stage
    stage = new Stage(viewportStage);
    Gdx.input.setInputProcessor(stage);

    // Setup font
    int Help_Guides = 12;
    int row_height = Gdx.graphics.getWidth() / 12;

    FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/PatrickHand-Regular.ttf"));
    FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
    parameter.size = 30;
    parameter.borderWidth = 1;
    parameter.color = Color.BLACK;
    BitmapFont myFont = generator.generateFont(parameter);
    generator.dispose();

    // Setup background pictures
    TextureAtlas textureAtlas = new TextureAtlas("atlas/onoff.atlas");
    TextureRegion backgroundTR1 = textureAtlas.findRegion("onoff_off");
    TextureRegion backgroundTR2 = textureAtlas.findRegion("onoff_on");

    // Setup TextButtons
    TextureRegionDrawable up1= new TextureRegionDrawable(backgroundTR1);
    TextureRegionDrawable down1= new TextureRegionDrawable(backgroundTR2);
    TextureRegionDrawable checked1= new TextureRegionDrawable(backgroundTR2);
    String text1 = "Deceptive dance in the poultry house.";
    ClickListener clickListner1 = new ClickListener() {
        @Override
        public void clicked(InputEvent event, float x, float y) {
            Gdx.app.log(Constants.TAG, "Button click received.");
            gsc.setState(GameStateController.State.PLAY);
        }
    };
    TextButton textButton1 = createTextButton(myFont, text1, up1, down1, checked1, clickListner1);

    // ... created some more buttons at this point

    // Setup Layout
    container = new Container<Table>();
    container.setBounds(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    container.setBackground(textureRegionDrawableBg);
    container.align(Align.bottomLeft);

    table = new Table();
    table.setBounds(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    table.setTouchable(Touchable.enabled);
    table.setDebug(true);
    table.debugAll();
    table.setBackground(textureRegionDrawableBg);
    table.setFillParent(true);
    table.align(Align.top);

    // TODO take care of scaling too when setting padding
    float padding = 10;
    table.row();
    table.add(textButton1).expandX().pad(padding);
    table.add(textButton2).expandX().pad(padding);
    table.row();
    table.add(textButton3).expandX().pad(padding);
    table.add(textButton4).expandX().pad(padding);
    table.row();

    container.setActor(table);
    stage.addActor(container);
}

private TextButton createTextButton(BitmapFont font, String text, TextureRegionDrawable up, TextureRegionDrawable down, TextureRegionDrawable checked, ClickListener clickListener) {
    Label.LabelStyle labelStyle = new Label.LabelStyle();
    labelStyle.font = font;

    Label label = new Label(text,labelStyle);
    label.setWrap(true);

    TextButton.TextButtonStyle style = new TextButton.TextButtonStyle();
    style.up =  up;
    style.down = down;
    style.checked = checked;
    style.font = font;

    TextButton button = new TextButton(label.toString(), style);
    //button.setSize(50,100);
    button.setLabel(label);
    button.getLabelCell().pad(20f);
    button.getLabel().setAlignment(Align.topLeft);
    button.setPosition(0,0);
    button.addListener(clickListener);

    return button;
}

@Override
public void update(float delta) {

}

@Override
public void render() {
    Gdx.gl.glClearColor(1f,1f,1f,1f);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    batch.setProjectionMatrix(camera.combined);
    batch.begin();
    stage.getViewport().apply();
    stage.draw();
    stage.act();
    batch.end();
}

@Override
public void dispose() {
    Gdx.app.log(TAG, "dispose(); Level Chooser");
    stage.dispose();
    bgPixmap.dispose();
    bgTexture.dispose();
}

@Override
public void resize(int w, int h) {
    Gdx.app.log(TAG, "resize() LevelChooserState;");
    stage.getViewport().update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);
    container.setFillParent(true); // makes sure the container will expand on resize
}
}

Upvotes: 0

Views: 710

Answers (2)

skymedium
skymedium

Reputation: 807

It works smoothly once I calculate and set the desired button manually. Width and height are calculated depending on screen size.

I changed this:

table.add(textButton1).expandX().pad(padding);

to this:

float buttonWidth = Gdx.graphics.getWidth()/2 * 0.9f;
float buttonHeight = buttonWidth * 1.3f;
table.add(textButton1).width(buttonWidth).height(buttonHeight).expandX().pad(padding);

Upvotes: 0

Yair Morgenstern
Yair Morgenstern

Reputation: 146

LibGDX uses real-pixel-to-screen-pixel mapping. You're using an ExtendViewport to initialize the game, which takes its minimum height and width from the actual window size in Gdx.graphics.getWidth(), Gdx.graphics.getHeight(). This means that the 'fake screen' you have, which you can then resize as much as you want, is actually determined by the size of the window.

I would advise you start with a fixed size for the ExtendViewport - say, 600 width, 400 height - and later you can change this to suit different sizes if necessary.

ExtendViewport with fixed sizes works fantastically well, even when displaying on extremely large screens.

Upvotes: 1

Related Questions