Jump to content

Texture loading and non-integer devicePixelRatio


mobileben
 Share

Recommended Posts

First time HTML5 dev here ... but I do have a background making games for other platforms. I'm currently establishing some foundational parts so I can build my first game. The current part I'm working on is handling resizes to the window. During this process, I was using one texture. I noticed that the image was drawing larger than it should. My code to create the application is:

const app = new PIXI.Application({
    width: gameArea.width,
    height: gameArea.height,
    view: <HTMLCanvasElement> document.getElementById('game-canvas'),
    antialias: true,
    transparent: false,
    backgroundColor: 0xFFFFFFFF,
    forceCanvas: canvasType == "canvas",
    resolution: window.devicePixelRatio});

As you can see, I am using `devicePixelRatio` for the resolution. I'm on a Mac, so this is 2. I realized the issue was needing an `@2x`. Once I did this, the image rendered at the correct size.

I recall reading that some Android devices have non-integer `devicePixelRatio` values. In these particular cases, what is the proper `@` suffix to use? For example, do you round down? Or does texture loading support modifying the resolution scale upon load or after it's been loaded? I'm trying to decide if I'm better off setting the resolution to 1 and handling resolution scaling myself. I've done that for other projects.

Another possible issue I could see was that I was going to probably have different scaled versions of assets depending on the overall size of the window. Let's call them lo, med, and high. Would this also imply I'd need extra sets (eg. @2x, @3x, @4x) of these sizes? 

Thanks!

Link to comment
Share on other sites

According to https://github.com/pixijs/pixi.js/blob/dev/packages/spritesheet/src/Spritesheet.js#L130 , currently its not possible to pass resolution to spritesheet parser from the code , only through json data.

You can  hack pixi spritesheet and loader that way it uses something from "metadata" field of loader, like pixi-spine does. If you feel like you can do it - PR will be appreciated.

As far as I know, people have only partial solutions for the problem with all those devices, you'll get a few advices in the thread, but nothing mind-breaking.

Link to comment
Share on other sites

Thanks for the reply! I was actually referring more to Texture versus Spritesheet. I took a look at the code, and it doesn't look accommodating for passing in options through the loader. Bear in mind I just started looking at the code and I'm not quite the JS guy. 

I've typically worked with aspect ratio layouts that used native resolutions and then matched the best fit sized assets (eg. small, med, large). Texture loading as well as generated metadata factored in that everything was being done at native resolutions. There are some issues related to this approach, although using points also suffers from the similar issues (eg. iPhone layout versus iPad).

I'll need to ponder this more as to how I want to manage this.

Link to comment
Share on other sites

@ivan.popelyshev thinking about this some more. What is there was another function created similar to getResolutionOfUrl which can be used to override resolution.

What I'm noticing is that a few places reference getResolutionOfUrl. So if we were to "catch all of the places" for overriding resolution, it would seem the good place would be to where getResolutionOfUrl is being applied.

I've experimented with creating new Texture objects after updating the BaseTexture resolution. This has no effect until something new is created from it. However, doing this doesn't work right if the BaseTexture is for a sprite sheet, since sprite sheet creation creates frames based on resolution. 

It would seem like a reasonably clean solution which would also make it a bit better for any strange devicePixelRatio Android uses. This is needed because without doing something like this, sprites/images are always the wrong size when rendered (unless of course the proper @#x trailer is used).

Link to comment
Share on other sites

Okay, thanks! I'll take a look. I'm probably going to try some experimental code with the concept I tried. It will provide some flexibility to people that don't use @2x, @3x, etc (ie. so they can do everything native resolution, which includes textures being treated as native).

Link to comment
Share on other sites

I have something that works. I'll put the solution here, as it isn't large, to get your feedback. I can create an issue and file a PR if you think it is worthwhile. I haven't yet committed the branch to my fork.

As a recap as to the why, I want to use native resolution for everything. Other OpenGL I've worked with is easy, since it is always native. Hence there is no meaning to @#x type files, for example. Everything is a pixel and the layers above handle any form of device pixel ratio type scaling. I wanted a good way to immunize against android as well as use the approach of small, med, and large type of assets the retina suffix named files.

This means my app is initialized like the following:

export const app = new PIXI.Application({
    width: gameArea.width,
    height: gameArea.height,
    view: <HTMLCanvasElement> document.getElementById('game-canvas'),
    antialias: true,
    transparent: false,
    backgroundColor: 0xFFFFFFFF,
    forceCanvas: canvasType == "canvas",
    resolution: 1});

What I have done is introduce the concept of a fallback. The idea is that if prefixing is used, then it uses the prefix. If not, it will check for a fallback. If no fallback value exists, then it will use the default. I chose this approach because it is naturally handled by the code. Moreover, I needed to add an extra value (the fallback) because I have not control of changing the value. So while the concept of the defaultValue is nice from an API perspective, it is only explicitly set by BitmapText and it takes the renderer resolution value. So we have no way of controlling it otherwise.

Code is as follows. I'm happy to make any changes/rename etc.

import { settings } from '../settings';

let FALLBACK_RESOLUTION_FOR_URL = 0;

/**
 * get the fallback resolution / device pixel ratio of an asset. This is used
 * in conjunction with getResolutionOfUrl
 *
 * @memberof PIXI.utils
 * @function getFallbackResolutionOfUrl
 * @return {number} fallback resolution / device pixel ratio. If 0, then ignore.
 */
export function getFallbackResolutionOfUrl() 
{
	return FALLBACK_RESOLUTION_FOR_URL;
}

/**
 * set the fallback resolution / device pixel ratio of an asset.
 *
 * @memberof PIXI.utils
 * @function setFallbackResolutionOfUrl
 * @param {number} value - the fallback value if no filename prefix is set.
 */
export function setFallbackResolutionOfUrl(value)
{
	FALLBACK_RESOLUTION_FOR_URL = value;
}

/**
 * get the resolution / device pixel ratio of an asset by looking for the prefix
 * used by spritesheets and image urls
 *
 * @memberof PIXI.utils
 * @function getResolutionOfUrl
 * @param {string} url - the image path
 * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set.
 * @return {number} resolution / device pixel ratio of an asset
 */
export function getResolutionOfUrl(url, defaultValue)
{
    const resolution = settings.RETINA_PREFIX.exec(url);

    if (resolution)
    {
        return parseFloat(resolution[1]);
    } 
    else 
    {
    	const fallback = getFallbackResolutionOfUrl();
    	if (fallback)
    	{
	        return fallback;
    	}
    }

    return defaultValue !== undefined ? defaultValue : 1;
}

To use, I'm simply doing the following after I create the Application.

PIXI.utils.setFallbackResolutionOfUrl(window.devicePixelRatio);

 

Link to comment
Share on other sites

There is one outstanding issue that I know of right now. Webfonts. When I create a PIXI.Text, it's still drawing larger based on the px I set. Not double, but about 25% larger. I noticed changing the value changes the level of blurriness. But too high and the font breaks down. The overall size remains the same.

Is this expected?

Another oddity I noticed. There seems to be a bug with set resolution The call to updateText/updateTexture never occurs. You need to do something else. So in my case, I called text.height afterwards. This would cause updateText/updateTexture to be called.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...