Question

The following code will erase a bitmap (brush akk droplet) from another bitmap (akka
The code works great on PC and pretty ok performacewise.

When i test it on more android devices, it doesn't work. No matter if is a high end device or a slower one. I've made some tests and found out the problem is lock() and unlock() functions from BitmapData. It simply doesn't update the image on device, only once.
I've tried to remove them, but the then it lags alot. Also the performace drop is noticeable on PC too. Does anyone know a solution, where am I doing wrong?

import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.geom.Point;
import flash.events.MouseEvent;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;

var m:BitmapData = new water_pattern;
var b:BitmapData = new droplet;

var bm:Bitmap = new Bitmap(m);

var bla = new blabla();
addChild(bla);
bla.addChild(bm);

function p($x,$y){


var refPoint = new Point($x-b.width/2,$y-b.height/2);
for(var i=0;i<b.width;i++)
for(var j=0;j<b.height;j++)
{
    var a:uint = (b.getPixel32(i,j)>> 24) & 0xFF;
    a=0xFF-a;
    var tp:uint = m.getPixel32(refPoint.x+i,refPoint.y+j);
    var tp_trans:uint = (tp >> 24)&0xFF;
    if(tp_trans>a){

        tp=(tp&0x00FFFFFF)|(a<<24);
        m.setPixel32(refPoint.x+i,refPoint.y+j,tp);
    }
}

//for(var k=0;k<10000000;k++){};
}
var k=1;
var md = function(e)
{
    m.lock();
    p(bm.mouseX,bm.mouseY);
    m.unlock();
};

bla.addEventListener(MouseEvent.MOUSE_DOWN,function(e)
{
    bla.addEventListener(Event.EXIT_FRAME,md);
});
bla.addEventListener(MouseEvent.MOUSE_UP,function(e)
{
    bla.removeEventListener(Event.EXIT_FRAME,md);
});

I've reworked the code :

public function draw($x, $y)
        {

            var refPoint = new Point($x - brush.width / 2, $y - brush.height / 2);
            var r:Rectangle = new Rectangle(refPoint.x, refPoint.y, brush.width, brush.height);

             var pv:Vector.<uint> = pattern.getVector(r);
             var bv:Vector.<uint> = brush.getVector(brush.rect);


             for (var i = 0; i < bv.length; i++)
                {
                    var a:uint = (bv[i]>>24) &0xFF;
                    a = 0xFF - a;
                    var tp:uint = pv[i];
                    var tp_trans:uint = (tp >> 24) & 0xFF;

                //  trace(a.toString(16) + " vs " + tp_trans.toString(16));
                    if (tp_trans > a)
                    {

                        tp = (tp & 0x00FFFFFF) | (a << 24);
                        //      trace("??>" + tp);
                        pv[i] = tp;
                    }
                }

               pattern.setVector(r, pv);
        }

Now it works, but still it is pretty slow on device. That before i saw Jeff Ward's comment, so i changed it to render mode on CPU. It works fast. The big problem is in CPU mode the game is very slow compared to GPU. Yet this script is fast on CPU but unusable slow on GPU.

So I've tried again the first code and surprise. It works. Jeff Ward, thank you, you're a genius. Now the question remains is why? Can someone please explain?

Was it helpful?

Solution

For your original question, sometimes GPU mode doesn't pick up changes into the underlying bitmapdata. Try any one of these operations after your unlock() to 'hint' that it should re-upload the bitmap data:

bm.filters = [];
bm.bitmapData = m;
bm.alpha = 0.98+Math.random()*0.02;

But as you found, uploading bitmapdata can be slow. To clarify GPU/direct render modes:

In GPU mode, changing any pixel in a Bitmap requires a re-upload of the full bitmap, so it's the size of Bitmap that's the limiting factor. In direct mode, it blits only the portions of the screen that have been updated. So I'd guess some parts of the game change a lot of the screen at once (slow in direct mode), whereas this effect changes a large bitmap, but only a little bit at a time (slow in GPU mode).

You have to get creative to maximize your performance wrt GPUs:

  1. In GPU mode, split the effect into many bitmaps, and only change as few as possible for any given frame. (medium effort)
  2. Use Starling GPU-accelerated framework and Starling filters (GPU shaders) to achieve your effect (effort depends on how much you have invested in your game already), see a couple of examples
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top