Yup, I know that everyone’s using TweenLite or Tween-something from GreenSock, but some time ago TweenLite wasn’t free for commercial use so I had to grab something different. I’ve found Twease – nice’n’small tweening lib with bezier tweening and several other fancy options. Then I’ve used to it, and it appeared in various projects. But there is annoying bug – Twease (newest version, 2.0) doesn’t render tween if your computer slowed down during the time the tween was taking place.
Imagine – you are building an app which initializes thousands of different stuff at the beginning and animates an alpha component of DisplayObject’s, so that they could appear after launching your app. But they won’t appear if somebody has 300Mhz Athlon or 1000 tabs opened in firefox.
Debugging a tweening classes is quite unpleasant, due to asynchronousity and hundreds of anonumous classes with strange short names and properties (yup, I think that majority of Tweening libraries are written in this hard-to-read way ;) ), so I never fixed this but used different hacks… until now. Jeez… the fix is simple and I could do this two years ago, but I wanted to write a pile of workarounds rather than to look into Twease’s code.
Ok, so finally, this is the fix –
1. You get rid of the “import flash.utils.getTimer;” at the beginning
2. You define some global vars
private static var frameCounter:uint = 0;
// 1000 miliseconds / 50 frames per second = 20ms for displaying one frame
private static var _ms:Number = 1000/50;
3. you write your own getTimer function
private static function getTimer():uint{
return frameCounter*_ms;
}
4. at the beginning of an “update” function you increment “frameCounter”:
public static function update(timerevent:Event):void {
frameCounter++;
(...)
5. And to add a pinch of a spice to our masterpiece, we add setter and getter of “_ms” variable:
public static function set fps( val:Number ):void{
_ms = 1000/val
}
public static function get fps( ):Number{
return 1000/_ms;
}
What we do here, we change Twease’s getTimer() method which gets time since flash vm start, to quasi-getTimer which returns the same, but with respect to frame-drops – so if we will loose some frames during tweening, our getTimer will slow down too. This is rather a hack than a bug fix – a real fix would involve changing something in Twease’s “render” function, to force rendering of the tween at the end.
At the beginning we should provide our movie’s frameRate:
Twease.fps = stage.frameRate;
Otherwise we assume that the framerate is 50. Ok, Im talkin obvious things right now so this is the end of this post. (“hacked” twease: here)
I wanted to make some kind of loader, which loads swf file, and accompanying asset files ( like for example dynamically loaded images or xml configuration files ) from one zip archive. Then we could have only 2 files – loader file and an archive with an application to load, instead of bunch of folders and files.
I wanted to make it cross-platform, so I’ve tried to do it in Adobe AIR ( standard flash player won’t allow us to create any files or folders ).
It would also serve as a Flex to AIR converter, becasue you add your Flex application’s files to data.zip archive, launch our AIR loader, and you have your Flex application running in AIR, without need to change xml files and so on.
We have AIR’s File class, which allows us to create folder and files.
So the basic idea is:
Yes… No. That’s not possible. You cannot run files from appStorageDir. Stupid sandbox violation errors will appear. SandBox in standalone applications… gr8 idea.
You will think of a hack: Let’s load this swf into ByteArray, and then execute this ByteArray using Loader class!!!
for example: var ldr:Loader = new Loader();
var fstream:FileStream = new FileStream();
fstream.open( YOUR_SWF_TO_LOAD , FileMode.READ );
ldr.load( fstream.readBytes() );
… Ok, it will run, but it won’t see any other files you’ve unpacked. Suppose we have config.xml in applicationStorageDirectory. It won’t see this config.xml, it will only see files in applicationDirectory – directory where our loader resides.
Ok: so let’s abandon this useless applicationStorageDirectory, and unpack everything to applicationDirectory. You think they will let you? Ha! You ingenuous little developer. They of course knows better what’s good for you. You can’t write to applicationDirectory. They say “it’s a bad practice”, and they also say “better use applicationStorageDirectory” They also say “make sandbox bridges to run active content from applicationStorageDirectory”. Sandbox bridges? This just some trivial feature in HTMLLoader class. SWF which runs in HTMLLoader is rendered by built-in flash AIR browser, and it runs 10x slower than it could in pure standalone flash player.
Ok, so we are still stuck with the problem – how to run this swf in AIR – and another problem – we can’t write to applicationDirectory. But wait… we can write to any other directory… So we can write to applicationDirectory too.
This is so stupid … Look, this causes security exception: var new_directory:File = File.applicationDirectory.resolvePath( "some_new_directory" ); // create path to "some_new_directory" in our loader's directory
new_directory.createDirectory(); // <---- ERROR
And this doesn’t: var new_directory:File = new File( File.applicationDirectory.resolvePath( "some_new_directory" ).nativePath );
new_directory.createDirectory();
We basically create new File object, with path equal to File.applicationDirectory/some_new_directory, but flash doesn’t know it’s our apps dir, so it doesn’t throw an exception. The rest is obvious – we execute .swf using File.applicationDirectory, because all files we need are actually in our application’s directory. And this is the simplest possible detour for these unnecessary sandbox “feature”.
And finally I’ve made this AIR swf loader, but… It appears, that files you load into AIR application has fewer fps, than they could have, when run stand-alone. These are the mxml sources, along with some additional dependencies, in case you’d ever want to load some swf’s dynamically from AIR.
It depends on “newzip”, nochump’s zip loading library, which I’ve modified slightly, to support asynchrounous loading ( then if you’ll have 30MB zip, your flash won’t hang due to timeout exception ). Just build .air package along with your data.zip archive ( the .swf files to launch ) and you’re ready to go. Sample data.zip included.
I had a few minutes to play with my old genie effect, so I’ve added two little features.
First one – the bounce effect. The genie seems to go too far, and then it comes back. It can be see when you open program windows ( not folder, but programs ) in OSX.
Second one – motion blur.
So there are two more parameters in the constructor, which tells GenieFx class , how far to bounce and how strong the motion blur will be:
new GenieFx( ( new demoBmp() ).bitmapData , /* object to animate - DisplayObject or BitmapData */
150 , /* x position of genie's "tail" */
0 , /* start from hidden image */ 0.3 , /* bounce. 1.0 = bounce as high as the image height, 0.0 = nobounce */
8.0 /* vertical blur to simulate motion blur */
);
Several experiments with flash pixel bender kernels and neuroscience math.
First is the 2D grid of coupled neural oscillators ( the neuroscientific equivalent of usual coupled oscillators descripted by some differential equations. Nice example is a double pendulum on youtube ).
So every pixel behaves like an oscillator and gives its energy to neighboring pixels. I’ve decided to store the energy in alpha component of 32 pixel.
On every render action, I’m stripping this alpha component and showing only 24 bit pixels:
mainBmp.bitmapData.applyFilter( mainBmp.bitmapData , mainBmp.bitmapData.rect , pt , shader );
bufBmp.bitmapData.copyPixels( mainBmp.bitmapData , mainBmp.bitmapData.rect , pt , null , null , false );
The last argument of copyPixels function tells flash to skip the alpha component. “shader” ( last argument of mainBmp’s applyFilter ) is the pixel bender filter.
This is the .as source: sine_pixel.as
And this is the kernel source: neur.pbk
Compiled kernel: neur.pbj
CLICK to see online simulation. Pretty cpu demanding, but it’s 256×256 oscillators grid. Click and drag on the stage like you were drawing, to start oscillation ( in the beginning the grid is synchronized ).
This is how it behaves in pure actionscript( flash player 10 needed, because I’ve optimized it using the Vector class ): sine_waves.swf … it has lower resolution though, 100×100. ( source )
The big resolution version ( 512×512 ): sine-hi.swf. CPU burning shader. I didn’t optimize it too much, maybe something can be changed to speed it up even more.
Ok, so that was the oscillation. There’s one more thing – grid of Sodium-Potassium neurons from previous post. I wanted to check if it’s going to be faster with pixel bender. And indeed – it is.
This is the source . I’m simulating current and the neuron response:
mainBmp.bitmapData.applyFilter( mainBmp.bitmapData , mainBmp.bitmapData.rect , pt , shader );
vBmp.bitmapData.copyChannel( mainBmp.bitmapData , mainBmp.bitmapData.rect , pt , BitmapDataChannel.RED, BitmapDataChannel.RED );
nBmp.bitmapData.copyChannel( mainBmp.bitmapData , mainBmp.bitmapData.rect , pt , BitmapDataChannel.BLUE, BitmapDataChannel.BLUE );
On every frame, I’m applying the shader on bitmap. Red component of pixel is the neuron response, green is the input current and blue is the gating variable. This time, I’m leaving alpha component alone. Because of this approach, I must copy RED channel from shaded bitmap to output bitmap, to see the graphical illustration of neuron response. The same thing happens with BLUE channel, which I copy to another bitmap. This is the kernel source: model.pbk. And this is the compiled kernel: model.pbj
I don’t want to bore you with neuron model theory, if you are here, you probably know what’s this. And if you don’t, you probably don’t want to know : )
I’ve made 3 experiments. All of them are based on real-life sodium – potassium Hodgkin-Huxley model.
First one is a 2d plot of current flow. The blue line is the input current, red and green ones are the neuron’s answer to the input current. Green is gating variable, red – neuron’s voltage.
It shows, how the current propagate in neurons connected into some kind of chain.
The third experiment pictures Hodgkin-Huxley’s model bifurcations from sample vector field. It’s shown as particles propagating thourgh the vector field. Click and hold the left mouse button to shoot the particles.