While playing with Alchemy, I focused a lot on C and C++ CG resources (like this great one).
Like many coders, I’ve always been fascinated by old school demoscene effects. ^^
Inspiration finally came, and I had good time producing some little experiments to play with.
Here’s one of them that I’m glad to share with you.
That’s two animated plasmas mixed together using same color palette. Color palette is splitted in 3 collections, one for red channel, another for green. Blue is unused. The last one is for handling pixels transparency.
[kml_flashembed movie="http://www.tweenpix.net/files/plasma.swf" width="400" height="400"/]
Some optimizations tricks deployed to get display smoothness:
- Plasmas are mixed together without blending. I’m drawing one pixel of each (with boolean checker) while generation.
- I use ByteArray (as video ram like low-level languages do) with BitmapData.setPixels for rendering. I discover it’s faster to not compute each channel if you don’t need it.
- As often, few as3 optimizations tips (Vector collections, int indexes, binary shifting for arithmetical operations, while loop without coordinates…)
Here’s the source code. Enjoy !
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.filters.BlurFilter;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.ByteArray;
[SWF( width="400", height="400", frameRate="25" , backgroundColor="0x000000")]
public class Plasma
extends Sprite
{
protected const w : int = 400;
protected const h : int = 400;
protected var bd : BitmapData;
protected var ba : ByteArray;
protected var position : uint;
protected var p : Point;
protected var rect : Rectangle;
protected var shifter : int;
protected var blur : BlurFilter;
protected const A : Vector. = new Vector.( 256, true );
protected const R : Vector. = new Vector.( 256, true );
protected const G : Vector. = new Vector.( 256, true );
protected var plasma : Vector.;
public function Plasma()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.LOW;
ba = new ByteArray();
p = new Point(0, 0);
rect = new Rectangle( 0, 0, w, h );
bd = new BitmapData( w, h, true, 0 );
blur = new BlurFilter( 4, 4, 1 );
addChild( new Bitmap( bd ) );
// generate palette
var i : int = 256;
while( --i > - 1 )
{
A[i] = int(128 + 128 * Math.sin( 3.1415 * i / 32));
R[i] = int(128 + 128 * Math.sin( 3.1415 * i / 16));
G[i] = int(128 + 128 * Math.sin( 3.1415 * i / 64));
}
// generate plasma
var x : int, y : int, l : int = w*h, b : Boolean = true;
plasma = new Vector.( l, false );
while( --l > - 1 )
{
x = l % w;
y = (l - x) / w;
var color : Number;
if ( b )
color = (128+(128*Math.sin(x/128))+128
+(128*Math.sin(y/128)))/2;
else
color = (128+(128*Math.sin(x/16))+128
+(128*Math.sin(y/8))+128
+(128*Math.sin((x+y)/16))+128
+(128*Math.sin(Math.sqrt(x*x+y*y)/8)))/4;
plasma[l] = color;
b = !b;
}
// init screen
for( x = 0; x < w; x++ )
{
for( y = 0; y < h; y++ )
{
var pos : Number = (x+(y*w))*4;
ba[pos] = 255;
ba[pos+1] = 0;
ba[pos+2] = 0;
ba[pos+3] = 0;
}
}
addEventListener( Event.ENTER_FRAME, enterFrame );
}
protected function enterFrame( e : Event ) : void
{
bd.lock();
var t : int = ++shifter, pos : int = w*h, palID : int, ID : int;
while ( --pos > - 1 )
{
palID = int((plasma[pos] + t) % 255);
// to process ARGB channels, same as pos *= 4;
ID = int(pos << 2);
ba[ID] = A[palID];
ba[ID+1]= R[palID];
ba[ID+2]= G[palID];
}
ba.position = 0;
bd.setPixels( rect, ba );
bd.applyFilter( bd, bd.rect, p, blur );
bd.unlock();
}
}
}
ça y est Francis devient demomaker ! (un peu tard mais bon…)
Posted by anto | 22 décembre 2008, 21 h 58 minJ’ai adapté ce code pour faire un plug-in pour Onyx-VJ, est-ce que je peux le publier sur mon blog avec le code source?
Thanks for sharing!
Posted by Batchass | 23 janvier 2009, 7 h 39 min@Batchass Pas de souci ! Enjoy !
Posted by Francis Bourre | 23 janvier 2009, 8 h 56 min