BlendMode.ALPHA gets really slow

Hello everyone!

This topic is somehow related to a topic I previously posted:

I am using this beginGradientFill code from the previous topic to make a hole on an image with BlendMode.ALPHA. If I do this once, the game runs perfectly. However, if I update the hole every frame (necessary to give a “breathing effect” to the hole) the framerate drops drastically.

The code is the following:

_img = new Bitmap(Assets.getBitmapData(srcImg));
_hole = new Shape();
addChild(_img);
addChild(_hole);
_colours = [0x000000, 0x000000];
_alphas = [0, 1];
_ratios = [0, 0xFF];
_matrix = new Matrix();

...

_matrix.createGradientBox(_holeRadius, _holeRadius, 0, _holeX - _holeRadius/2, _holeY - _holeRadius/2);
_hole.graphics.clear();
_hole.graphics.beginGradientFill(GradientType.RADIAL, _colours, _alphas, _ratios, _matrix);
_hole.graphics.drawRect(0,0,1920,1080);
_hole.graphics.endFill();

Thank you!

I believe once you use this, it triggers software rendering, which could explain the performance difference. Can you cache the result using bitmapData.draw, or does it need to continue to dynamically update?

Unfortunately I have to dinamically update it. I have a sinoidal function operating on the radius of the hole like this:

This video shows the game running with the gradientFill approach, not making a hole on an image. If I try to make this effect happen on an image the game is not playable =/

Do you happen to know any alternative to get this kind of effect?

Hmm, I suppose there are two main ways to go about it:

  1. You have a large black object, and you punch a hole through it

  2. You have a round object that fades to black that you lay over things, then you mask the rest of things out

If I were to try and think of a faster way to implement it, I might try doing path #1 using a large object (that I rendered overly large) then I try scaling it up or down based on the shadow size

If I were to try #2, I would use a scrollRect to do the full alpha cut-off, then draw a shape in order to handle the remaining part of the hole. This I would also consider caching and scaling as needed

Thanks! I will try both approaches and post the results soon =)

EDIT

Just thought a little bit more about the two approaches and I won’t be able to use them.

#1 would work with a full black background, but the image I need to puch a hole through has a texture, so it is visible that it is scaling

#2 is fine for the cenario I showed on the video, but the next step in the game is to make this hole open and show the whole scene. If I do this, I get the framerate drop again because the scrollRect would have to have the size of the whole screen.

I guesst I will just keep using the gradient fill and give up on using that image. Thanks for the help!

Had a similar problem.

Tried drawing my way around it.

public static inline function fillExceptHole(graphics:Graphics, background:String, x:Float, y:Float, radius:Float):Void {
    var topBorder:Float = y-radius;
    if(topBorder < 0) {
        topBorder = 0;
    }
    var leftBorder:Float = x-radius*.8;
    if(leftBorder < 0) {
        leftBorder = 0;
    }
    var rightBorder:Float = x+radius*.8;
    if(rightBorder > Application.SCREEN_WIDTH) {
        rightBorder = Application.SCREEN_WIDTH;
    }
    var bottomBorder:Float = y+radius;
    if(bottomBorder > Application.SCREEN_HEIGHT) {
        bottomBorder = Application.SCREEN_HEIGHT;
    }

    beginFill(graphics, background);

    //top
    moveTo(0, 0); //1
    lineTo(Application.SCREEN_WIDTH, 0); //2
    lineTo(Application.SCREEN_WIDTH, y); //3
    lineTo(rightBorder, y); //4
    curveTo(x, topBorder, leftBorder, y);
    lineTo(0, y); //7
    lineTo(0, 0); //1
    drawPath(graphics);

    //bottom
    moveTo(0, y); //1
    lineTo(leftBorder, y); //2
    curveTo(x, bottomBorder, rightBorder, y);
    lineTo(Application.SCREEN_WIDTH, y); //5
    lineTo(Application.SCREEN_WIDTH, Application.SCREEN_HEIGHT); //6
    lineTo(0, Application.SCREEN_HEIGHT); //7
    lineTo(0, y); //1
    drawPath(graphics);
    graphics.endFill();
}

//util functions
private static var commands:Vector<Int> = new Vector<Int>();
private static var data:Vector<Float> = new Vector<Float>();

public static inline function moveTo(x:Float, y:Float):Void {
    commands.push(GraphicsPathCommand.MOVE_TO);
    data.push(x);
    data.push(y);
}
public static inline function lineTo(x:Float, y:Float):Void {
    commands.push(GraphicsPathCommand.LINE_TO);
    data.push(x);
    data.push(y);
}
public static inline function curveTo(controlX:Float, controlY:Float, anchorX:Float, anchorY:Float):Void {
    commands.push(GraphicsPathCommand.CURVE_TO);
    data.push(controlX);
    data.push(controlY);
    data.push(anchorX);
    data.push(anchorY);
}
public static inline function drawPath(graphics:Graphics):Void {
    graphics.drawPath(commands, data);
    commands = new Vector<Int>();
    data = new Vector<Float>();
}

is this on html? i’m trying to do a similar thing and can’t figure out how to get blendmode.alpha working at all

I don’t believe it’s currently implemented on HTML5