Question

I am loading a batch of 150 HD images into my app - it is basically a 3D view of an object. Once I load the image files using Loader instances I store the loaders' first child's bitmapdata in a Vector. When all of the loaded, I want to begin to "rotate" the object = meaning I am simply swapping the images. I take the Vector where I have the bitmapdatas and draw them onto a canvas bitmapdata one after the other. No science there, it all works as intended.

The problem is that once all the images are loaded and stored in a vector and BEFORE they are drawn to the canvas, they are not in the memory. That means that the first rotation of my 3D object (-> all 150 images drawn) is really slow. After the first rotation there is no problem and all is fluid. My question is: is there a way to force the images to get loaded into the memory without drawing them onto the stage? I expected that they would simply get loaded to memory once they are loaded to the app (Wrong!).

I tried to use addChild() instead of drawing them to a canvas bitmap, same result. I don't think the code is necessary but just in case:

private var _loaders:Vector.<Loader>;
private static const NAME:String = "img_00";
private static const MIN:uint = 0;
private static const MAX:uint = 150;
private var _loaded:uint = 0;
private var _currentFrameIndex:uint = 0;
private var _canvas:Bitmap;
private var _bitmaps:Vector.<BitmapData>;
private var _destPoint:Point;

public function loadImages():void {
    var s:String;
    for(var i:int=MIN; i<=MAX; i++) {
        if(i < 10) s = "00" + i;
        else if(i < 100) s = "0" + i;
        else s = i.toString();
        var loader:Loader = new Loader();
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadHandler);
        loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, loadHandler);
        loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loadHandler);
        loader.load(new URLRequest("images/JPEG/"+ NAME + s + ".jpg"));
        _loaders.push(loader);
    }
}

private function loadHandler(e:Event):void {
    _loaded++;

    if(_loaded > (MAX - MIN)) {
        _bitmaps = new Vector.<BitmapData>(_loaders.length);
        for(var i:int=0; i<_loaders.length; i++) {
            var loader:Loader = _loaders[i];
            _bitmaps[i] = Bitmap(loader.getChildAt(0)).bitmapData;
            loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadHandler);
            loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, loadHandler);
            loader.contentLoaderInfo.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, loadHandler);
        }
        setFrame(0);
        dispatchEvent(new Event(LOAD_COMPLETE));
    }
}

public function setFrame(frame:uint):void {
    if(frame >= 0 && frame < _bitmaps.length) {
        _currentFrameIndex = frame;
        var bmpData:BitmapData = _bitmaps[_currentFrameIndex];
        _canvas.bitmapData.copyPixels(bmpData, bmpData.rect, _destPoint);
    }
}
Was it helpful?

Solution

"Not in the memory" means that the images are loaded, but not yet decoded, and this decode is done on the fly, and this takes the time you observe as slowness. You can attempt to "virtually" rotate the image by having a bitmap that's not yet added to stage to be the reference to each of the bitmapDatas of your vector. Make a progress bar that shows how much of the vector has already been decoded, and once this happens, display the bitmap and give the user smooth rotation.

addEventListener(Event.ENTER_FRAME,prerender);
var b:Bitmap=new Bitmap();
/* optional
    b.x=stage.stageWidth;
    b.y=stage.stageHeight;
    addChild(b);
*/
var vi:int=0;
var sh:Shape=new Shape();
sh.graphics.lineStyle(4,0,1); // a simple progress bar
sh.graphics.moveTo(0,0);
sh.graphics.lineTo(100,0);
sh.scaleX=0;
sh.x=stage.stageWidth/2-50; // centered by X
sh.y=stage.stageHeight/2;
addChild(sh);
function prerender(e:Event):void {
    if (vi==_bitmaps.length) {
        // finished prerender
        removeEventListener(Event.ENTER_FRAME, prerender);
        removeChild(sh);
        // removeChild(b); if optional enabled
        setFrame(0);
        return;
    }
    b.bitmapData=_bitmaps[vi];
    vi++;
}

Also, it's always better to assign the bitmapData property to a Bitmap object if you don't plan to have that bitmapdata changed. So, instead of your _canvas.bitmapData.copyPixels(bmpData, bmpData.rect, _destPoint); you just do _canvas.bitmapData = bmpData; and it'll work.

UPDATE: Your issue might as well nail to the last point, that is assigning instead of copying. If your destPoint is something else than (0,0), you just make another Bitmap object on top of your _canvas with desired offset, and assign bitmapdatas in there. I have remembered that when I first made multiple animated objects based on a single Vector.<BitmapData> like yours, and tried doing copyPixels(), my animations were jittering and not displaying proper frames, but once I did _bitmap.bitmapData=_bitmaps[currentFrame] everything went as smooth as it should be.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top