Particle Painter
/**
* Copyright leichtgewicht ( http://wonderfl.net/user/leichtgewicht )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/rlp2
*/
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.text.TextField;
public class Drawing extends Sprite {
internal static const AMOUNT_PARTICLES: int = 20;
internal static const ANGLE_PER_PARTICLE: Number = 2 * Math.PI / AMOUNT_PARTICLES;
internal static const PARTICLE_POWER_DECAY: Number = 0.7;
internal static const PARTICLE_POWER_MIN_LIMIT: Number = 0.0001;
internal static const COLOR_PER_DRAW: Number = 0x08;
internal static const DISTANCE_LIMIT: Number = 4;
private var _bitmap: Bitmap;
private var _bitmapAsVector: Vector.<uint>;
private var _width: Number;
private var _height: Number;
private var _fullRect: Rectangle;
private var _out: TextField;
private var _down: Boolean;
private var _formerX: Number;
private var _formerY: Number;
private const _particleList: ParticleList = new ParticleList();
public function Drawing() {
addEventListener( Event.ENTER_FRAME, drawParticles );
stage.addEventListener( MouseEvent.MOUSE_DOWN, startDraw );
stage.addEventListener( MouseEvent.MOUSE_UP, stopDraw );
_height = stage.stageWidth;
_width = stage.stageHeight;
_formerX = mouseX;
_formerY = mouseY;
stage.frameRate = 60;
addChild( _bitmap = new Bitmap( new BitmapData(_width, _height, false ) ) );
_out = new TextField();
_out.height = stage.stageHeight;
_out.width = stage.stageWidth;
_fullRect = new Rectangle( 0, 0, _width, _height );
_bitmapAsVector = _bitmap.bitmapData.getVector( _fullRect );
for( var x: int = 0; x < _width; ++x )
{
for( var y: int = 0, yReal: int = 0; y < _height; ++y, yReal += _width )
{
_bitmapAsVector[ yReal + x ] = 0xFFFFFF;
}
}
}
private function startDraw( event: MouseEvent ): void {
_down = true;
}
private function stopDraw( event: MouseEvent ): void {
_down = false;
}
private function sendParticles(): void {
var xStep: Number = (mouseX-_formerX) / AMOUNT_PARTICLES;
var yStep: Number = (mouseY-_formerY) / AMOUNT_PARTICLES;
for( var i: int = 0, x: Number = _formerX, y: Number = _formerY; i< AMOUNT_PARTICLES; ++i, y+=yStep, x+=xStep ) {
var particle: Particle = Particle.getOrCreate();
particle.x = x;
particle.y = y;
particle.power = 1.0;
particle.directionX = Math.random();
particle.directionY = Math.random();
particle.partRight = 1.0;//particle.directionX < 0.0 ? -particle.directionX : 0.0;
particle.partLeft = 1.0;//particle.directionX > 0.0 ? particle.directionX : 0.0;
particle.partBottom = 1.0;//particle.directionY < 0.0 ? -particle.directionY : 0.0;
particle.partTop = 1.0;//particle.directionY > 0.0 ? particle.directionY : 0.0;
particle.partTopLeft = particle.partTop * particle.partLeft;
particle.partTopRight = particle.partTop * particle.partRight;
particle.partBottomLeft = particle.partBottom * particle.partLeft;
particle.partBottomRight = particle.partBottom * particle.partRight;
//_out.appendText( "\nNew particle: " + particle.directionX + ":" + particle.directionY + ":" + particle.x + ":" + particle.y + ":" + particle.speed ) ;
_particleList.add( particle );
}
}
private function drawParticles( event: Event = null ): void {
if( _down ) //&& Math.abs(mouseX - _formerX) + Math.abs( mouseY - _formerY ) < DISTANCE_LIMIT )
{
sendParticles();
}
_formerX = mouseX;
_formerY = mouseY;
var current: ParticleListNode = _particleList.first;
while( current ) {
_particleList.next = current.next;
var particle: Particle = current.particle;
var draw: Number = particle.power;
var x: int = int( particle.x );
var xValue: Number = particle.x - x;
var y: int = int( particle.y );
var yBase: int = y * _width;
var yValue: Number = particle.y - y;
particle.x += particle.directionX * particle.power;
particle.y += particle.directionY * particle.power;
if( x > 0 && y > 0 && x < _width-1 && y < _height-1 )
{
var p1: uint = yBase + x;
var p2: uint = yBase + x + 1;
var p3: uint = yBase + _width + x;
var p4: uint = yBase + _width + x + 1;
var vx: Number = ( 0x3fc - ( _bitmapAsVector[p1] & 0xFF ) * particle.partTopLeft + ( _bitmapAsVector[p2] & 0xFF ) * particle.partTopRight + ( _bitmapAsVector[p3] & 0xFF ) * particle.partBottomLeft + ( _bitmapAsVector[p4] & 0xFF ) * particle.partBottomRight ) / 0x3fc;
//_out.appendText( "\n"+ vx );
particle.power += vx * 0.001;
var cBase: Number = COLOR_PER_DRAW * particle.power;
var a1: int = ( xValue + yValue ) * cBase;
var a2: int = ( xValue + (1.0-yValue) ) * cBase;
var a3: int = ( (1.0-xValue) + yValue ) * cBase;
var a4: int = ( (1.0-xValue) + (1.0-yValue) ) * cBase ;
//_out.appendText( "\n"+xValue+","+yValue );
a1 = a1 | a1 << 8 | a1 << 16;
a2 = a2 | a2 << 8 | a2 << 16;
a3 = a3 | a3 << 8 | a3 << 16;
a4 = a4 | a4 << 8 | a4 << 16;
var c1n: int = _bitmapAsVector[ p1 ] - a1;
_bitmapAsVector[ p1 ] = c1n > 0 ? c1n : 0;
var c2n: int = _bitmapAsVector[ p2 ] - a2;
_bitmapAsVector[ p2 ] = c2n > 0 ? c2n : 0;
var c3n: int = _bitmapAsVector[ p3 ] - a3;
_bitmapAsVector[ p3 ] = c3n > 0 ? c3n : 0;
var c4n: int = _bitmapAsVector[ p4 ] - a4;
_bitmapAsVector[ p4 ] = c4n > 0 ? c4n : 0;
}
particle.power *= PARTICLE_POWER_DECAY;
if( particle.power <= PARTICLE_POWER_MIN_LIMIT ) {
_particleList.remove( current );
Particle.dispose( particle );
}
current = _particleList.next;
}
_bitmap.bitmapData.setVector( _fullRect, _bitmapAsVector );
}
}
}
import flash.utils.Dictionary;
class ParticleList {
internal var first: ParticleListNode;
internal var next: ParticleListNode;
internal var last: ParticleListNode;
internal function add( particle: Particle ): void {
var node: ParticleListNode = ParticleListNode.getOrCreate();
node.particle = particle;
if( !first )
{
first = node;
}
else
{
last.next = node;
node.prev = last;
}
if( !next ) {
next = node;
}
last = node;
}
internal function remove( node: ParticleListNode ): void {
if( node == first ) {
first = node.next;
} else {
node.prev.next = node.next;
}
if( node == last ) {
last = node.prev;
} else {
node.next.prev = node.prev;
}
if( node == next ) {
next = node.next;
}
ParticleListNode.dispose( node );
}
}
class ParticleListNode {
private static var _pool: Vector.<ParticleListNode> = new Vector.<ParticleListNode>();
internal static function getOrCreate(): ParticleListNode {
if( _pool.length > 0 )
{
return _pool.pop();
}
return new ParticleListNode();
}
internal static function dispose( node: ParticleListNode ): void {
_pool.push( node );
node.next = null;
node.prev = null;
node.particle = null;
}
internal var next: ParticleListNode;
internal var prev: ParticleListNode;
internal var particle: Particle;
}
class Particle {
private static var _particles: Vector.<Particle> = new Vector.<Particle>();
internal static function getOrCreate(): Particle {
if( _particles.length > 0 )
{
return _particles.pop();
}
return new Particle();
}
internal static function dispose( particle: Particle ): void {
_particles.push( particle );
}
internal var x: Number;
internal var y: Number;
internal var power: Number;
internal var directionX: Number;
internal var directionY: Number;
internal var partLeft: Number;
internal var partRight: Number
internal var partTop: Number;
internal var partBottom: Number;
internal var partTopLeft: Number;
internal var partTopRight: Number
internal var partBottomLeft: Number;
internal var partBottomRight: Number
}