## Webcam Particles

Inspired by Andrés fur-experiments and the perlin-particles by Joa this little Webcam idea crossed my mind.
It uses a perlin noise force to position the particles. The particles save their position, have a lifespan and color information.

The code for the particle effect is fairly simple. First there is the Particle class:

public class Particle
{
public var next: Particle;

public var posX: Number;
public var posY: Number;
public var velocityX: Number;
public var velocityY: Number;

public var livespan: int;
public var age: int;
public var color: int;
}

Then the actual force and rendering class. First setup the input and output:

private function init():void
{
var cam:Camera = Camera.getCamera();
cam.setMode( 640, 480, 30 );
_video = new Video( cam.width, cam.height );
_video.attachCamera( cam );
_input = new BitmapData( _dim.width, _dim.height, true, 0 );

_output = new BitmapData( _dim.width, _dim.height, true, 0 );
_outputBlur = new BitmapData( _dim.width, _dim.height, false, 0 );
addChild( new Bitmap( _output ) );

var scale: Number = 4;
_noise = new BitmapData( _dim.width / scale, _dim.height / scale, false, 0 );
_force = new BitmapData( _dim.width, _dim.height, true, 0 );
_scaleMatrix = new Matrix();
_scaleMatrix.scale( scale, scale );
}

Then the setup the particles:

private function setupParticles(): void
{
var p: Particle;

var n: int = NUM_PARTICLES;

p = _particles = new Particle();

while( --n > -1)
{
p = p.next = new Particle();

p.posX = Math.random( ) * _dim.width;
p.posY = Math.random() * _dim.height;

p.velocityX = Math.random();
p.velocityY = Math.random();
p.livespan = Math.random() * 20;
p.age = 0;
}
}

The last part is a render-loop / enterframe handler:

private function render( e: Event ): void
{
_input.draw( _video );

_p0.x += SPEED;
_p0.y -= SPEED;
_p1.x -= SPEED;
_p1.y += SPEED;

_noise.perlinNoise( 10.0, 10.0, 2, 2, false, true, BitmapDataChannel.GREEN | BitmapDataChannel.BLUE, false, _octaves );
_force.draw( _noise, _scaleMatrix );

var particle: Particle = _particles.next;

do
{
force = _force.getPixel( particle.posX, particle.posY );

++particle.age;

if( particle.age > particle.livespan )
{
particle.posX = Math.random() * _dim.width;
particle.posY = Math.random() * _dim.height;
particle.color = _input.getPixel( particle.posX, particle.posY );
particle.age = 0;
}
else
{
if( ( force >> 8 & 0xff ) > 0x80 )
++particle.posX;
else
--particle.posX;
if( ( force & 0xff ) > 0x80 )
++particle.posY;
else
--particle.posY;

particle.posX += particle.velocityX;
particle.posY += particle.velocityY;

a = 0xff * ( particle.age / particle.livespan ) >> 24;
r = particle.color >> 16;
g = particle.color >> 8;
b = particle.color ;

_outputBlur.setPixel( particle.posX, particle.posY, ( a << 24 | r << 16 | g << 8 | b ) );
}

particle = particle.next;

}
while( particle );

_output.copyPixels( _outputBlur, _outputBlur.rect, origin );
_outputBlur.applyFilter( _outputBlur, _outputBlur.rect, origin, filter );
}