Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

6 years ago by Joncom

Just thinking out loud, but any input or feedback would be great too!

I'd like to add an options/settings menu to a game, and a "scale" setting would be nice.

What considerations must be made to change the scale on-the-fly, after the game has initialized?

1. A copy of the original 1x image must be kept because it would be used to generate all non-1x scaled images.

2. After changing the scale, loop through images in ig.Image.cache and call .resize for any image which does not have a current scale version of itself in cache.

3. .resize must use the original 1x image version mentioned in step 1, not the scaled version.

4. Consider using localStorage or some other local file storage method to cache scaled images, especially larger ones, because scaling is a CPU intensive task and can cause a particularly noticeable delay if the game is already running.

6 years ago by vincentpiel

I think that changing the scale is quite an operation that could justify storing the target scale in local storage, and have a whole game reload in case of scale change. So you both let your user change scale, but the game will re-launch after a change (it should be handled in an 'option' menu, that would be launched from the start menu).

6 years ago by Joncom

Some PC games require a restart for certain settings to take effect, but doesn't it seem like the better experience would be to not force a restart? What are the advantages/disadvantages?

6 years ago by vincentpiel

To be able to hot resize you need to :
- keep the original version of your assets.
- resize them on resolution change, which
is at least partially handled by Impact. (but since
i rewrote ig.Image, i never tested).
- if you have both hd/sd assets and loaded
sd ones, think about reloading them in hd.
- re-think about the world View -> screen View
function you want to use (crisp, ...).
- if you have svg's, and if you cached them in canvas
to enhance speed on drawImage friendly Browsers,
then re-print them at right scale.

So in fact, there's no real issue for a small game with
graphics not that big.
With big graphics, it's almost a no-go to keep them like
twice in memory i guess.

My point was to say that for such a rarely used feature, having
a document reload on scale change should be pretty good allready.
If you wish, you could store also in local storage that the user was
in setting menu, so you can put him/her again in the same place,
and maybe ask for confirmation. But some kind of animation must
be ongoing if the user has to say that now performances are ok now.

6 years ago by lTyl

Why do you want to be able to dynamically change the scale Joncom? If it is to maintain the nearest-pixel scale look for assets that are blown up beyond their original size, most major browsers (IE10, Safari, Firefox, Opera, not chrome yet :( ) have built-in nearest-neighbor scaling support and can be activated like this:

                    var ctx = ig.system.canvas.getContext('2d') || ig.system.canvas.getContext('webgl-2d');
                    // Set browser-based nearest neighbour scaling to true if the browser supports it
                    if (ctx.msImageSmoothingEnabled
                        || ctx.webkitImageSmoothingEnabled
                        || ctx.mozImageSmoothingEnabled
                        || ctx.oImageSmoothingEnabled
                        || ctx.imageSmoothingEnabled){
                        ctx.msImageSmoothingEnabled = true; // Set IE10 smooth scaling
                        ctx.webkitImageSmoothingEnabled = true; // Set Chrome/Safari smooth scaling
                        ctx.mozImageSmoothingEnabled = true; // Set Firefox smooth scaling
                        ctx.oImageSmoothingEnabled = true; // Set opera smooth scaling
                        ctx.imageSmoothingEnabled = true; // Future proofing
                    }

Here is the change, using the default Impact font file, blown up to 1920x1080 resolution:
http://tderen.com/images/impact/image-smoothingOff.png
http://tderen.com/images/impact/image-smoothing.png

6 years ago by Joncom

Quote from lTyl
Why do you want to be able to dynamically change the scale Joncom?
Yes, to maintain the nearest neighbor look.

most major browsers (IE10, Safari, Firefox, Opera, not chrome yet :( ) have built-in nearest-neighbor scaling support
Very cool!! I did not know support was that good already. However, too bad about Chrome!! That's kind of a deal breaker for me... :(

6 years ago by Joncom

@lTyl: Having trouble getting nearest neighbor pixel drawing to occur in Firefox. The following is in my main.js init:
if (ig.system.context.msImageSmoothingEnabled ||
        ig.system.context.webkitImageSmoothingEnabled ||
        ig.system.context.mozImageSmoothingEnabled ||
        ig.system.context.oImageSmoothingEnabled ||
        ig.system.context.imageSmoothingEnabled) {
    ig.system.context.msImageSmoothingEnabled = true; // Set IE10 smooth scaling
    ig.system.context.webkitImageSmoothingEnabled = true; // Set Chrome/Safari smooth scaling
    ig.system.context.mozImageSmoothingEnabled = true; // Set Firefox smooth scaling
    ig.system.context.oImageSmoothingEnabled = true; // Set opera smooth scaling
    ig.system.context.imageSmoothingEnabled = true; // Future proofing
}

No luck when I use false instead of true either.

Here is the function I use to make the canvas fill the screen:
onresize: function(event) {
    var scale = 3;
    var width = Math.floor(window.innerWidth/scale);
    var height = Math.floor(window.innerHeight/scale);
    ig.system.resize(width, height);
    ig.system.canvas.style.width = '' + (width * scale) + 'px';
    ig.system.canvas.style.height = '' + (height * scale) + 'px';
}

Any idea why smoothing is not working as desired? It's blurry :(

6 years ago by lTyl

@Joncom: I'm still experimenting with this stuff myself mind you, support is better now compared to when Dom wrote the 'Drawing Pixels is Hard' article (here: http://phoboslab.org/log/2012/09/drawing-pixels-is-hard), but it is still shit. Try adding the following CSS style to your #canvas in your stylesheet (In index.html by default)
            image-rendering: -webkit-optimize-contrast;
            image-rendering: optimize-contrast;
            image-rendering: -moz-crisp-edges;
            -ms-interpolation-mode: nearest-neighbor;

This should get built-in nearest neighbour scaling in latest Opera, Firefox and (sometimes) IE8 & IE10. IE is behaving weird for me, the earlier versions of IE (IE 8) acknowledge -ms-interpolation-mode, IE9 ignores it and IE11 makes it obsolete for msImageSmoothingEnabled, but it still behaves...randomly. Here is a test case you can use to test browser compatibility: http://tderen.com/labs/examples/nn_scaling/. It uses context.imageSmoothingEnabled, and works with Chrome, latest Firefox and IE11 (Maybe 10). For Opera, you need to use the CSS tag above as it ignores the context smoothing flag. Unfortunately, Safari seems to ignore everything because Apple.

Also, here is my resize code:
            resize: function () {
                if (_s.USE_UPSCALING){ 
                    var windowWidth = window.innerWidth,
                        windowHeight = window.innerHeight,
                        // Figure out how much we have to scale by.
                        scaleX = windowWidth / _s.INTERNAL_X_RESOLUTION,
                        scaleY = windowHeight / _s.INTERNAL_Y_RESOLUTION,
                        // Get the current screen ratio and the optimal ratio.
                        currentRatio = windowWidth / windowHeight,
                        targetRatio = _s.UPSCALE_X_RESOLUTION / _s.UPSCALE_Y_RESOLUTION,
                        optimalRatio = Math.min(scaleX, scaleY);

                    if (arc.Utils.closeEnough(currentRatio, targetRatio, _s.UPSCALE_TARGET_THRESHOLD)){
                        // Current window size supports the target resolution ratio, upscale to the set value
                        ig.system.canvas.style.width = _s.UPSCALE_X_RESOLUTION + "px";
                        ig.system.canvas.style.height = _s.UPSCALE_Y_RESOLUTION + "px";
                        ig.mark("System resize: Target Resolution");
                    } else {
                        // Current window size does not support the target ratio. Resize to the optimal ratio to avoid blur
                        ig.system.canvas.style.width = (_s.INTERNAL_X_RESOLUTION * optimalRatio) + "px";
                        ig.system.canvas.style.height = (_s.INTERNAL_Y_RESOLUTION * optimalRatio) + "px";
                        ig.mark("System resize: Optimal Resolution");
                    }

                    // If upscaling is off, but resizing is on, we resize the game screen to the internal resolution
                } else if (_s.RESIZE_GAME){ // Set the game canvas size to the internal resolution
                    ig.system.resize(_s.INTERNAL_X_RESOLUTION * canvasWidthPct * (1 / ig.system.scale), _s.INTERNAL_Y_RESOLUTION * canvasHeightPct * (1 / ig.system.scale));
                    ig.system.size = Math.min(ig.system.width, ig.system.height);
                }
            },

Basically, you set a target resolution (The resolution you build the game for) and then it compares your target resolution vs the current window size. If it can support the target resolution; we blow up 100%, otherwise we only blow up to the lowest of the width/height, which drastically helps with the blur.

6 years ago by Joncom

@lTyl: Great, thank you!!

6 years ago by collinhover

If it helps, Impact++ does per entity scaling and dynamic scaling without reloading the page or restarting the game. You need to cache the original image as you suggested, and I also cache the scaled versions in case multiple entities at different scales use the same image (and you don't need localStorage, just keep it in the image). This is a bit more memory intensive and can be disabled, but saves extra calculations when changing scales. I should note that I also did something similar to @ITyl's suggestion, but because I need a solution that works without relying on browser implementation I also use `get/setImageData`. The performance hit is not even noticeable, unless you either use huge images with large scales, tween the scales, or something equally ridiculous.

The relevant code is in ig.Image:
https://github.com/collinhover/impactplusplus/blob/master/lib/plusplus/core/image.js
(you can also check out ig.GameExtended's resize method for more dynamic resizing code)
Page 1 of 1
« first « previous next › last »