Gamua / Starling-Framework

The Cross Platform Game Engine
http://www.starling-framework.org
Other
2.85k stars 819 forks source link

ContentScaleFactor alters appearance of scale9grid corners #886

Closed kevinfoley closed 8 years ago

kevinfoley commented 8 years ago

The corners of an Image with scale9Grid applied are affected by scaleFactor in an undesirable way. Fidelity is lost if the scaleFactor is greater than 1, even after correcting the dimensions of the scale9Grid.

scale9 corners change

Sample code (use with attached image)

public class Game extends Sprite {

    private var am1:AssetManager;
    private var am1Loaded:Boolean = false;
    private var am2:AssetManager;
    private var am2Loaded:Boolean = false;

    public function Game() {
        am1 = new AssetManager(1);
        am2 = new AssetManager(2);
        am1.enqueue("Button.png");
        am2.enqueue("Button.png");

        am1.loadQueue(am1Progress);
        am2.loadQueue(am2Progress);
    }

    private function am1Progress(value:Number):void {
        if (value >= 1) {
            am1Loaded = true;
            if (am2Loaded) {
                doDemo();
            }
        }
    }

    private function am2Progress(value:Number):void {
        if (value >= 1) {
            am2Loaded = true;
            if (am1Loaded) {
                doDemo();
            }
        }
    }

    private function doDemo():void {
        Starling.current.stage.color = 0xffffff;    

        var t1:Texture = am1.getTexture("Button");
        var t2:Texture = am2.getTexture("Button");

        var image1:Image = new Image(t1);
        image1.width = 200;
        image1.height = 80;
        image1.x = 20;
        image1.y = 50;
        image1.scale9Grid = new Rectangle(3, 3, 59, 24);
        addChild(image1);

        var image2:Image = new Image(t2);
        image2.width = image1.width;
        image2.height = image1.height;
        image2.x = image1.x + image1.width + 50;
        image2.y = image1.y;
        image2.scale9Grid = new Rectangle(2, 2, 26, 9);
        addChild(image2);
    }
}

Button.png: button

PrimaryFeather commented 8 years ago

I don't think what you're seeing is actually an issue with the scale9-grid, but just the way the scale factor works.

To see what I mean, take the scale9 grid out of the equation. When you add the images with the two textures directly to the stage, without a scale9 grid, it will look like this:

buttons_1x

The problem: the stage itself is displayed with a contentScaleFactor of 1 (the viewport size equals the stage size). Textures with a scale factor of 2 need to be used on a stage with a contentScaleFactor of 2 to be able to show all their pixels.

What the scale factor is typically used for is retina displays. E.g. on an old iPhone 3G, you set both stage and viewPort width to 320. On an iPhone 4, you leave the stage width at 320, but set the viewPort width to 640. That allows you to create an app for both screens with the same coordinate system. However, it will also make everything blurry on the iPhone 4. To fix that, you provide textures with a scale factor of 2.

Now, here's what the sample above looks like on a retina display (contentScaleFactor = 2):

buttons_2x

See? Now the left texture (scale = 1) looks a little blurry, and the right one is perfectly sharp. In other words: images look best if the scale factor of their textures equals the contentScaleFactor of the stage.

Does it make sense now?

kevinfoley commented 8 years ago

I understand how the contentScaleFactor is typically used, but I feel that the behavior with the scale9Grid is undesirable. Try commenting out the scale9Grids in the above code; then you get two equally sized rectangles that look identical in every way. It's strange that adding the scale9Grid changes the appearance of only one of the two rectangles.

PrimaryFeather commented 8 years ago

Hm, I don't know, but for me this behavior seems logical. 😕

When I comment out the scale9Grids, the texture is scaled to exactly the size that's desired, distorting them in whatever way necessary. That's why they look identical. By assigning your own scale, you actually "wipe out" the scale factor.

But when you use scale9Grid-scaling, you tell the object that its corners should remain unchanged, and only the "cross" in the middle should change its size / be distorted. And looking at the image, this is exactly what happens.

scale9-overlay

When you look at those red corners, they are identical to what you get when you assign the scale9Grid. They don't change, and that's exactly what's supposed to happen. Only the areas in the middle are distorted.

Does that help in any way? Or maybe I'm not getting the point you actually mean?

PrimaryFeather commented 8 years ago

Any more feedback from your side, Kevin?

kevinfoley commented 8 years ago

As a real-world example of how this can be a problem, some of Josh's sample Feathers themes for Feathers 3 only have one set of textures and use a scaleFactor of 2 for the texture atlas. Take for example the MetalWorksMobile theme, in which many UI objects use scale9Grid and have rounded corners. On screens where the Starling contentScaleFactor comes out to 1, the corners lose so much detail they no longer appear to be rounded.

Maybe this is a completely subjective issue, but to me it seems like a design flaw.

PrimaryFeather commented 8 years ago
On screens where the Starling contentScaleFactor comes out to 1, the corners lose so much detail they no longer appear to be rounded.

In my opinion, there should either be two (or more) sets of textures in that theme then (so that there is a specific set of textures for each scale factor). Otherwise, you either lose sharpness (atlas scale factor: 1) or fidelity (atlas scale factor: 2). The whole idea behind the scale factor is that you can provide multiple sets of textures that behave identically, even though they have a different number of pixels.

I think I understand your point, but in my opinion, everything is working as designed here. If I'd change the scale9 implementation to work around this, the results wouldn't fit into the whole concept, IMHO. But, as you say, probably it's simply a subjective issue; I do see the logic behind your argument, as well.

Nevertheless, since I think this is working as expected, I'll close this issue for now. If anyone else wants to chime in and join you, Kevin, in trying to persuade me that this is a design flaw — please feel free to open it up again. :smile:

Cheers!