Auto scaling for high DPI

My goal is to have a particular rectangle and piece of text be about an inch wide regardless of the screen DPI of the machine my app is running on.

It seems like my only option right now is to set allow-high-dpi="true" in project.xml and remember to scale every component by stage.window.scale

Here’s my code:

package;

import openfl.display.Bitmap;
import openfl.display.Sprite;
import openfl.Assets;
import openfl.text.TextField;
import openfl.text.TextFormat;
import openfl.text.TextFormatAlign;
import openfl.system.System;
import openfl.system.Capabilities;

class Main extends Sprite {
	
    public function new() {
		super();

        // Scale
        trace('stage.window.scale ${stage.window.scale}');
        trace('Capabilities.screenDPI ${Capabilities.screenDPI}');

        var bold14Font = new TextFormat("Arial", 14, 0xff0000);

        var navbarBackground = new Sprite();
        addChild(navbarBackground);

        navbarBackground.graphics.beginFill(0x2c3e50);
        navbarBackground.graphics.drawRect(0, 0, 100, 100);
        // navbarBackground.scaleX = stage.window.scale;
        // navbarBackground.scaleY = stage.window.scale;

        var text2 = new TextField();
        text2.defaultTextFormat = bold14Font;
        text2.text = 'Inside container';
        // text2.scaleX = stage.window.scale;
        // text2.scaleY = stage.window.scale;
        navbarBackground.addChild(text2);

        var text1 = new TextField();
        text1.defaultTextFormat = bold14Font;
        text1.text = 'Floating text';
        text1.x = 100;
        // text1.scaleX = stage.window.scale;
        // text1.scaleY = stage.window.scale;
        addChild(text1);
	}
}

This produces an image where everything is half as big as I want (use the traffic lights for reference):

02%20PM

If I uncomment all those .scaleX and .scaleY lines, then I get the following. The blue square is the expected size, but the “Floating text”'s left side is no longer at the right edge of the blue square. Also, the “Inside container” text got double the scaling (inheriting some from the parent Sprite).

32%20PM

To get it to look how I’d like, then, I have to do the following:

navbarBackground.scaleX = stage.window.scale;
navbarBackground.scaleY = stage.window.scale;

text2.scaleX = stage.window.scale / text2.parent.scaleX;
text2.scaleY = stage.window.scale / text2.parent.scaleY;

text1.x = 100 * stage.window.scale;
text1.scaleX = stage.window.scale;
text1.scaleY = stage.window.scale;

With the above code, the high DPI version looks like this:

24%20PM

And the low DPI version looks like this:

48%20PM

Is there a way to globally scale the whole coordinate system so that I don’t have to individually scale every component (especially once I have a deep tree of nested components)?

Edit: I should mention that I’m NOT targeting HTML5. I’m targeting iOS/Android/Mac/Linux/Windows

Wow, no answer for this. I am in need of the same answer

You don’t need to scale every display object individually. You can scale the root object, and everything that it contains will be scaled automatically.

class Main extends Sprite {
    public function new() {
		super();
		scaleX = stage.window.scale;
		scaleY = stage.window.scale;
	}
}

Super easy!

The only tricky part is if you use stage.stageWidth and stage.stageHeight. Those will be at the HiDPI sizes. So, if you need those values for calculating layouts, you’ll need to do something like: stage.stageWidth / stage.window.scale

By the way, in the next OpenFL update (the version is currently expected to be 9.2.0), everything will be scaled automatically on HiDPI screens when you specify allow-high-dpi="true" in project.xml. Even the stageWidth and stageHeight will be scaled properly. When you upgrade, you should be able to remove any code that manually accounts for HiDPI screens. Alternatively, if you prefer the old behavior, you can specify the openfl_dpi_aware haxedef in your project.xml to opt out.

4 Likes

Thanks for the info, I’m using 9.1.0
mark for this

Thanks this solved my issue as well.