UPDATE: I intended to post the source for this a long while ago (after cleaning it up), but I never got around to it. Here it is in it’s current state.
I wanted to see how far I could push that exploding Actionscript 3.0 code – see if Flash could handle updating each animating pixel every frame, while playing a video, then blurring it. Sure enough, it can! It did take further optimization from the version I posted the other day – including swapping copyPixels with getPixel/setPixel, and removing an anonymous function call (wow that was expensive!). Here it is:
Note: This WILL run like slush on the debug player. I don’t know why. If anyone knows why, please let me know!
Well I guess technically the pixels don’t explode as much as the DisplayObject explodes into pixels! I recently needed an effect that would make a bitmap image look sparkley, so I did some goggling, and game across a Firefly particle effect on a blog post belonging to Erik Hallander (at least I think so, the blog has been down for months, so I can’t double check). This pretty impressive effect looks like the following example (I hope reposting it here is not a problem).
Note: This is a modified version of the original adding the Stats.as box, and autolooping – and removes the actual firefly affect (I didn’t need that part for my purposes).
Very nice start! I don’t get an FPS problem – on my computer the example above rocks 62/60 fps (25% CPU on my Core 2 Duo)! So FPS was not the big problem. This example uses over ~19-23MB of RAM (with a lot of fluctuation)! And that is with 2×2 pixels, it goes up higher with 1×1 pixels. Additionally, this example already has an optimization in it to skip over empty (black) pixels in the DisplayObject it works on – which leads to a significant RAM savings.
Using the display list this way – and two filters per DisplayObject – it began causing the player to kick up a lot of invalid BitmapData/null reference errors (which I’m guessing is what happens when you run out of memory, since many many checks confirmed that the BitmapData was not invalid) – especially when I tried to make it work on 1×1 pixels to animate every pixel.
So the first thing I did was to clean up some of the obvious stuff, to bring down the memory usage – in the original blog post, Erik noted that this was unoptimized code, so I knew what I was getting into. I did things like remove the extra nested DisplayObjects (each pixel was a subclasses Sprite instance, with a BitmapData added to it), and cleaned up extra variables that were laying around, moved a lot of things inline, reused as many variables as I could, cutting down on object instantiation – and followed a lot of the other tips in a conveniently timed ByteArray post. Doing that really helped – I cut the memory use about in half – and on the initial animation (a black and white logo) the affect seemed worked quite well. But it didn’t scale well – larger images simply wouldn’t work.
I still wanted to use this affect, and I’ve seen many thousands of pixels being animated before – so I knew it was possible. So a radical departure. I’ve been reading about drawing directly to Bitmaps for quite a while, and that was going to be my path. So more optimizations – removed the display list code completely, changed the Pixel class to a simply property class (where are the enums?!), and used that to store information about where in the original source to look for the pixel data as well as other relevant animation data (most of which was already done for me – thanks!) for each pixel block. I also removed dependence on TweenMax – which is what the original uses for all the animations – and used the easing equations directly, within an ENTER_FRAME event.
The result is a RAM reduction by 25% and a steadier memory usage, coming in at ~5MB with 4x as many pixels (and roughly the same amount of CPU). The changes utilize copyPixels and a linked list, with an accumulation buffer like effect – for a total of 3 bitmaps (the original, which is rendered from the DisplayObject and stored, the scattered one the pixels get copied into, and the copy of that that gets blurred by the BlurFilter – a hidden memory cost illuminated by Thibault Imbert).
There are further optimizations that can be used as well (and should really be used for full image per pixel animations) – such as writing to an opaque BitmapData, rather than one with Alpha, and reducing the BlurFilter quality – getting a better handle on type marshaling, etc. It might also be faster to store the RGB value of each pixel, and draw those directly instead of using copyPixels, but I haven’t tried that yet.
I got so much help from the Flash community on this, that it would be irresponsible not to share this back, so feel free to check out the source.
Some Notes:
The memory usage applies to both swfs on this page – so you can’t see the memory usage difference in these examples. I quoted the standalone Flash Player in this post.
Also, I’m getting some kind of performance problem in plugin browsers (everything except IE) on Windows, and on every browser on mac but Firefox which is limiting both of these to around 30FPS. I have no idea what’s causing it.
On the code quality – the code isn’t all that messy IMHO, but it is not well documented, and a lot of the configuration hooks I left in are not really being utilized in a decent API – I may refactor at some point to clean that up. There is also a limitation of the skip pixel check that will keep it from working well for greater than 1×1 pixel size (since it only checks the top left corner of the size rect).