Feature request for Flash Player 11 – Single DisplayObject in multiple containers by Thibault Imbert

As you may know, since Flash Player 8 thanks to the BitmapData class, you are able to create a single BitmapData instance and reference it through multiple instance of the Bitmap class, this way you are reusing the BitmapData instance without recreating it.

In the following code, we are not reusing the BitmapData class, but we are creating for each iteration and new BitmapData instance which is very costly in memory :

var sourceImage:BitmapData;
var imageContainer:Bitmap;
for ( var i:int = 0; i< 300; i++ )
{
sourceImage = new BitmapData (20, 20, false, 0xF0D062);
imageContainer = new Bitmap ( sourceImage );
addChild ( imageContainer );
imageContainer.x = ( imageContainer.width + 8 ) * Math.round (i % 20);
imageContainer.y = ( imageContainer.height + 8 ) * Math.floor (i / 20);
imageContainer.z = Math.random()*1000;
imageContainer.alpha = Math.random();
imageContainer.scaleX = imageContainer.scaleY = Math.random();
imageContainer.rotation = Math.floor ( Math.random()*360 );
imageContainer.alpha = Math.random();
}

Result :

A Flash animation should have appeared here, but it seems that your browser has an older version of the Flash Player or it is not installed at all. Please, install the last release of the Flash Player now, then reload this page.

The code above cost around 600kb in memory. Now here is a way to get the exact same result but only cost 90kb in memory, thanks to the first line of code :

var sourceImage:BitmapData = new BitmapData (20, 20, false, 0xF0D062);
var imageContainer:Bitmap;
for ( var i:int = 0; i< 300; i++ )
{
imageContainer = new Bitmap ( sourceImage );
addChild ( imageContainer );
imageContainer.x = ( imageContainer.width + 8 ) * Math.round (i % 20);
imageContainer.y = ( imageContainer.height + 8 ) * Math.floor (i / 20);
imageContainer.z = Math.random()*1000;
imageContainer.alpha = Math.random();
imageContainer.scaleX = imageContainer.scaleY = Math.random();
imageContainer.rotation = Math.floor ( Math.random()*360 );
imageContainer.alpha = Math.random();
}

Result :

A Flash animation should have appeared here, but it seems that your browser has an older version of the Flash Player or it is not installed at all. Please, install the last release of the Flash Player now, then reload this page.

Here, a single BitmapData instance is used and shown through the multiple Bitmap instances. The Bitmap instances are acting as screens and as soon as you update the BitmapData source, everything is updated, simple and efficient :

stage.addEventListener ( MouseEvent.CLICK, changeColor );

function changeColor  ( e:MouseEvent ):void
{
sourceImage.fillRect ( sourceImage.rect, Math.random()*0xFFFFFF );
}

Which gives the following result (click to change color) :

A Flash animation should have appeared here, but it seems that your browser has an older version of the Flash Player or it is not installed at all. Please, install the last release of the Flash Player now, then reload this page.

Now, why do I talk about this ? Well, the concept of having a single reference and being able to reference it and show it is great, first for memory optimization but also in terms of simplicity of coding.

What would be great is having the same feature as we have here for BitmapData but for traditional DisplayObjects. Flash Player 9 introduced the concept of reparenting, which means that if you call the addChild method and pass a DisplayObject which is already nested in a container, calling such a method will make it leave it's original container to get into the new one. This feature is great, but what could be even nicer is a way to allow the developer to say : Hey, this time please don't reparent this DisplayObject, just show it in the new container just like the Bitmap class does with BitmapData. Like BitmapData, if the original DisplayObject is modified (stopped, rotated, etc) everything is updated.

In a game, let's say you have a wall made of stars, currently what you would have to do is instanciate as much as stars as you need to create the wall, or better, create a rasterized version of the star movieclip using BitmapData instances and emulate the MovieClip through Bitmap instances referencing the BitmapData frames, but BitmapData.draw() does not allow you to capture also nested animations in MovieClip on each frame, and some other problems would be hard to deal with, as a result this could be made easier if implemented natively.

To resume, the idea is to have different instances (enveloppes) hosting a single and unique content represented by a DisplayObject behaving as the source.

It would be really nice to have this in the Flash Player, if you like the idea please vote for this feature !
This could make it happen one day ! :)

Comments (22)

  1. Mr.doob wrote::

    I do agree on this. But, have you think about the case of interactivity? If you rollover a displayobject and the color changes, all of them should change, isn’t it? Won’t that confuse a bit the developer?

    With BitmapData works fine because they aren’t interactive.

    Wednesday, May 6, 2009 at 4:09 pm #
  2. Pleh wrote::

    Also wouldn’t you need to place each DisplayObject that is referenced in more than one place into another DisplayObject to act as a container so you can position them in different places?

    In your example above, creating a star field out of shared sprites would not work by just attaching the same sprite to the same parent multiple times because the sprite only has 1 set of X,Y coordinates, meaning if you moved one sprite, all sprites would move on top of each other, which is obviously no good, so you would need to create a wrapper sprite which you add to the container then add your star sprite to that wrapper. Not really making the coding process easier, but actually complicating it a bit.

    Its a good idea don’t get me wrong, I just think it needs to be thought out a bit more.

    Wednesday, May 6, 2009 at 4:18 pm #
  3. dmitry zhelnin wrote::

    also there can be a problem with recursive including display objects. and what about DisplayObject.parent ?

    i think that this idea is wrong. if it could be implemented, it will make things too difficult

    @Mr.doob: with BitmapData it works fine not because they aren’t interactive, but because bitmapData is only a property of display objects, and Bitmap objects still must be different for the same bitmapData

    Wednesday, May 6, 2009 at 4:47 pm #
  4. Tek wrote::

    Not 100% sure, but I think something equivalent exists in Silverlight. I remember a SL preso where a sprite was broken into pieces and each pieces continue to render the animation. The guy tell us that the consumed memory was the same with only one sprite or many because only one sprite was used as source of the rendering.

    Because of what Mr.Doob says, I can’t considerate how to implement this functionnality, without the concept of a source DisplayObject. A DisplayObject that acts as the source of the rendering for any other DisplayObject that need it. So we need a special DisplayObject that only resides in memory, and that we cannot add as a child.

    It will probably need that all DisplayObject have a new property like : DisplayObject.displaySource:SpecialDisplayObject

    I vote for. This concept is so natural to me. I just hope that the implementation will be well thought.

    Wednesday, May 6, 2009 at 4:59 pm #
  5. Joa Ebert wrote::

    Thibault, you can save even more memory if your BitmapData instances have an odd width/height. This will prevent the FlashPlayer from calculating mipmaps.

    For DisplayObjects I completly disagree. The Flash DisplayList is a pretty straigh forward implementation and you have to think about a lot of problems. What about capturing/bubbeling of events? If your DisplayObject is in 20 different DisplayObjectContainer instances, who will receive the event?

    I would suggest a different model. More like using the decorator pattern. For instance:

    var myClone: DisplayObject = new VirtualDisplayObject(original);

    We have implemented something like this in our DOM and it is very nice. File systems have this feature too (softlinks). That way events and everything else would work the same way as before.

    Wednesday, May 6, 2009 at 5:00 pm #
  6. ynk wrote::

    At school i had to do a vectorial framework which can do this :)

    Mail me for a very quick demo !

    Wednesday, May 6, 2009 at 5:09 pm #
  7. Tek wrote::

    Hmm, correction … there is no need to create a special DisplayObject. Any DisplayObject could be used as display source of any other. Even a child DisplayObject … still better.

    I think the Flash Player dev team could use a cached bitmap from DisplayObject.cacheAsBitmap as display source for the rendering of all others DisplayObject.

    Wednesday, May 6, 2009 at 5:10 pm #
  8. Pleh wrote::

    I like Tek’s idea, having a source display object that cannot be added to the stage will save a lot of confusion.

    This will then work in the exact same way as how the BitmapData and Bitmaps do now (You can’t add BitmapData to the stage)

    Wednesday, May 6, 2009 at 5:14 pm #
  9. Tek wrote::

    @Pleh > Your right but finally, I’m now thinking that the dev will have the choice to add the source DisplayObject to the DisplayList or not. It adds more flexibility in use of this functionnality.

    Wednesday, May 6, 2009 at 5:20 pm #
  10. Pleh wrote::

    Agreed, as long as you aren’t able to add a display object to more than 1 container I think it will work fine.

    Wednesday, May 6, 2009 at 5:28 pm #
  11. Thibault Imbert wrote::

    Hi,

    Cool to see that this generates a lot of discussion ! :)

    Mrdoob,

    To me, as soon as the timeline itself of any container is altered (stop, play, etc.) all the other containers should reflect those changes. But if you fade the container (the enveloppe only) it is only altering the current container and not any all the others. Imagine a simple logo in a Flash website, with a simple motion tween, you have this logo 5 times in the website, instead of creating 5 instances, you just show it in multiple containers with different scaling, if you update it at runtime all the other containers reflect the changes, could be cool no ?

    Pleh,

    Yes of course you would have to create containers to show the DisplayObject source.

    Joa,

    Instances would be different here, so this would not cause any problems in terms of event propagation. Different instances as enveloppes hosting the same content with a unique source. The concept of VirtualDisplayObject is nice, I also like Tek’s idea with the displaySource property.

    ynk,

    Nice, I want to see it ! :)

    Tek,

    Something almost similar seesm to exist in WPF. I will look at it. Yes a displaySource property would be great, nice idea. A native rasterizer would be even better but well, that’s a different story ;)

    Wednesday, May 6, 2009 at 7:22 pm #
  12. Rezmason wrote::

    This is weird to think about, but I don’t see why it wouldn’t work. Recursing wouldn’t be a big deal, because recursion in the display list goes top down, from the parent objects to the children, and never the other way around. We’re basically talking about children having multiple parents, which has few problems.

    But.

    Interactive stuff does pose a problem. Say we have a Sprite called “ball” (of type Ball) that’s a child of two Sprites, “room1″ and “room2″ (of type Room), that’re in a Sprite “house” (type House). If we click the Ball in room2, we are also clicking the Ball in room1; they are the same Ball instance. The Ball will need to understand its context; each interactive event would need a Vector. of parents that represent the context in which the ball is clicked, and would look like this for the case I’m describing:

    function reactToClick(event:MouseEvent):void {
    trace(event.chainOfCommand); // [Object Room], [Object House], [Object MainTimeline], [Object Stage]
    }

    Does that make sense?

    Wednesday, May 6, 2009 at 9:36 pm #
  13. Tek wrote::

    I don’t understand why the discussion deviates on the interactivity problem.

    Thibault, tell me if I’m wrong, but what Thibault wants is not to be able to duplicate the DisplayObject with all its interactivity, but only the raster version of it (frame after frame of course).

    We do not need to copy the real same DisplayObject several times on the screen, all with the same interactivity. With the DisplayObject.displaySource idea I talk above, if you want to do it, just add several instances (created with the new operator I mean) of the same DisplayObject, and gave them the same displaySource. Each will act with its own interactivity. If you really need the interacting DisplayObject to have a different appearance, just set its displaySource property to null.

    Thursday, May 7, 2009 at 12:05 am #
  14. Thibault Imbert wrote::

    Hi Rezmason,

    If we click the Ball in room2, we are only clicking the Ball in room2. I am only talking about feeding different instances (enveloppe) with the same source. Each container is different and keep and remains its own interacvity, nothing is broken or modified.

    Yes Tek, you are right !

    Thursday, May 7, 2009 at 1:21 am #
  15. Rezmason wrote::

    Ohhh! Now I get it. I completely agree.

    A while ago I made a Shape subclass that does what you’re asking for, with some extra brains that improve efficiency. The problem is, its update() method needs to be called manually, whereas a Bitmap object will change its appearance as long as the BitmapData object isn’t locked.

    If you want this functionality immediately, it’s part of the Blix library: http://rezmason.net/portfolio2009/files/sachsj_blix.zip

    I’m gonna go vote.

    Thursday, May 7, 2009 at 4:31 am #
  16. Tink wrote::

    You could just draw you DisplayObject onto a BitmapData each frame?

    Thursday, May 7, 2009 at 1:50 pm #
  17. Thibault Imbert wrote::

    Hi Tink,

    Yes, that’s what I do now with the slicing approach I posted a little time ago. There are different problems with this.

    First, it would consume a lot of memory if your animation is long, but the main problem is that it’s almost hard to get a perfect rasterizer when DisplayObject have multiple filters and a complex hierarchy, when drawing a frame with the BitmapData.draw() method, you cannot capture all the nested animations occuring in nested MovieClip’s on that frame. A workaround is ask to the animator to do all his animations on one timeline only and do not nest any animations.

    But I agree, this a feature I would love to see one day (http://www.bytearray.org/?p=290), a native rasterizer which would give crazy performance improvements especially for complex DisplayObjects. Even if this would consume some memory, you could do the choice of consuming more memory but get awesome rendering performance improvements. That’s a choice !

    Thibault

    Thursday, May 7, 2009 at 5:26 pm #
  18. 2morrowMan wrote::

    Thibault Imbert, you are designer or programmer? You write like flash designer not a real programmer.

    Friday, May 8, 2009 at 10:13 pm #
  19. Thibault Imbert wrote::

    Hi 2morrowMan,

    I do both today in Flash. That’s interesting, what makes you think it’s written like a Flash designer ? :)

    Thibault

    Friday, May 8, 2009 at 10:30 pm #
  20. Thibault Imbert wrote::

    Thanks Rezmason,

    I will check your Blix lib :)

    Thibault

    Friday, May 8, 2009 at 11:05 pm #
  21. liuhuan wrote::

    cool!!!!!Thanks

    Sunday, May 17, 2009 at 10:59 am #
  22. Hieu Vo wrote::

    Cool, I have never thought that if we change the sourceBitmapData from which all Bitmaps have been created, the bitmaps will change also ; )

    Saturday, July 18, 2009 at 12:30 pm #

Trackback/Pingback (1)

  1. [...] контейнеры. С подробностями можно ознакомиться здесь. Голосовать или нет — решать вам. Но, по-моему, это [...]