/**
* Copyright lespleen ( http://wonderfl.net/user/lespleen )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/4KVF
*/
// forked from esimov's Lissajous Curve
/* @title LISSAJOUS CURVE
*
*@see http://wonderfl.net/c/7Cxn
*@see http://jacksondunstan.com/articles/1190
*
*@author spleen666@gmail.com
*
* Added setVector + LUT optmizations.
*
*
*/
package
{
import flash.geom.Point;
import flash.filters.BlurFilter;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import net.hires.debug.Stats;
[SWF (backgroundColor = 0xffffff, width = '465', height ='465')]
public class LissajousCurve extends Sprite
{
private const WIDTH:Number = stage.stageWidth
private const HEIGHT:Number = stage.stageHeight;
private var _dist:Number;
private var _angleX:Number = 0;
private var _angleY:Number = 0;
private var _speedX:Number = Math.random() * 0.1 - 0.05;
private var _speedY:Number = Math.random() * 0.1 - 0.05;
private var _points:Array = [];
private var _bmd:BitmapData;
private var _bmp:Bitmap;
private var sqrtLUT:LUT;
private var sinLUT:LUT;
private var cosLUT:LUT;
/* pixel vector*/
public var _pixels:Vector.<uint>;
private var stageRect:Rectangle;
private var zeroPoint:Point = new Point();
private var blurFilter:BlurFilter = new BlurFilter(3,3,3);
public function LissajousCurve()
{
if (stage)
{
init(null)
}
else
{
addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
}
}
private function init(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.frameRate = 60;
stage.fullScreenSourceRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
stageRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
start();
}
private function start():void
{
//Wonderfl.capture_delay (15);
_bmd = new BitmapData( stage.stageWidth, stage.stageHeight, true, 0xffffffff);
_pixels = _bmd.getVector( stageRect )
_pixels.fixed = false
_bmp = new Bitmap(_bmd);
_bmp.smoothing = true;
addChild(_bmp);
addChild( new Stats() );
sqrtLUT = new LUT(2, 200000, Math.sqrt);
sinLUT = new LUT(2, LUT.TWO_PI, Math.sin);
cosLUT = new LUT(2, LUT.TWO_PI, Math.cos);
stage.addEventListener(MouseEvent.CLICK, click, false, 0, true);
stage.addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
private function click(e:MouseEvent):void
{
stage.removeEventListener(Event.ENTER_FRAME, loop);
_bmd.fillRect( stageRect, 0xffffffff);
_pixels = _bmd.getVector( stageRect )
resetFunc();
stage.addEventListener(Event.ENTER_FRAME, loop,false, 0, true);
}
/**
* "Extremely Fast Line Algorithm"
* @author Po-Han Lin (original version: http://www.edepot.com/algorithm.html)
* @author Simo Santavirta (AS3 port: http://www.simppa.fi/blog/?p=521)
* @author Andrea Bovo - added setVector lookup
*/
private function efla( pixels:Vector.<uint>, x:int, y:int, x2:int, y2:int, color:uint): void
{
var shortLen:int = y2-y;
var longLen:int = x2-x;
var yLonger:Boolean
var index:uint =0
if ( (shortLen ^ (shortLen >> 31)) - (shortLen >> 31) > (longLen ^ (longLen >> 31)) - (longLen >> 31))
{
shortLen ^= longLen;
longLen ^= shortLen;
shortLen ^= longLen;
yLonger = true;
}
else
{
yLonger = false;
}
var inc:int = longLen < 0 ? -1 : 1;
var i:int = 0
var multDiff:Number = longLen == 0 ? shortLen : shortLen / longLen;
if (yLonger)
{
for (i = 0; i != longLen; i += inc)
{
//bmd.setPixel(x + i*multDiff, y+i, color);
pixels[ xyToOff(x + i*multDiff, y+i, WIDTH) ] = color
}
}
else
{
for (i = 0; i != longLen; i += inc)
{
//bmd.setPixel(x+i, y+i*multDiff, color);
pixels[ xyToOff( x+i, y+i*multDiff, WIDTH)] = color
}
}
}
private function xyToOff( x:int , y:int , width:int ): int {
return (y * width) + x;
}
private function resetFunc():void
{
_points.splice(0, _points.length);
_dist = 0;
_angleX = Math.random() * Math.PI / 2;
_angleY = - Math.random() * Math.PI / 4;
_speedX = Math.random() * 0.1 - 0.05;
_speedY = Math.random() * 0.1 - 0.05;
}
private function loop(e:Event):void
{
var p0:Node = new Node();
var p1:Node = new Node();
var dx:Number;
var dy:Number;
var color:uint = 0xff000000;
var i:int = 0;
var len:int = _points.length;
p1.x = (WIDTH/2) * (1 + cosLUT.valTrig(_angleX) )
p1.y = (HEIGHT/2) *(1 + sinLUT.valTrig(_angleY) )
_angleX += _speedX;
_angleY += _speedY;
_speedX += Math.random() * 0.01 - 0.005;
_speedY += Math.random() * 0.01 - 0.005;
_speedX *= 0.995;
_speedY *= 0.995;
_bmd.lock()
for (i = 0; i < len; i++)
{
p0 = _points[i];
dx = p0.x - p1.x;;
dy = p0.y - p1.y;
_dist = sqrtLUT.val( dx * dx + dy * dy ) ;
if (_dist < 1)
{
return
}
else
if (_dist < 40)
{
var alpha:uint = (color >> 24) & 0xff;
var tone:uint = (color >> 24) & 0xff;
var min:Number = Math.min(alpha - _dist / 80, 0xff);
var max:Number = Math.max(117, min);
alpha = (alpha < 0xff) ? max : min;
tone = tone < 255 ? tone - (_dist * 0.48) : 255 - (_dist * 0.78);
color = (alpha << 24) | (tone << 16) | (tone << 8) | tone;
efla( _pixels, p0.x, p0.y, p1.x, p1.y, color);
}
}
_points.push(p1);
_bmd.setVector( stageRect, _pixels);
_bmd.applyFilter( _bmd, stageRect, zeroPoint, blurFilter);
_bmd.unlock();
}
}
}
class Node
{
public var x:Number;
public var y:Number;
public function Node():void
{
}
}
/*********************************************************************************************************/
/**
* A generic lookup table useful for caching the results of a function
* @author Jackson Dunstan
*/
class LUT
{
/** 2 * PI, the number of radians in a circle*/
public static const TWO_PI:Number = 2.0 * Math.PI;
/** The static TWO_PI cached as a non-static field*/
private const TWO_PI:Number = LUT.TWO_PI;
/** Table of function values*/
public var table:Vector.<Number>;
/** 10^decimals of precision*/
public var pow:Number;
/**
* Make the look up table
* @param max Maximum value to cache
* @param numDigits Number of digits places of precision
* @param func Function to call to generate stored values.
* Must be valid on [0,max).
* @throws Error If func is null or invalid on [0,max)
*/
public function LUT(numDigits:uint, max:Number, func:Function)
{
var pow:Number = this.pow = Math.pow(10, numDigits);
var round:Number = 1.0 / pow;
var len:uint = 1 + max*pow;
var table:Vector.<Number> = this.table = new Vector.<Number>(len);
var val:Number = 0;
for (var i:uint = 0; i < len; ++i)
{
table[i] = func(val);
val += round;
}
}
/**
* Look up the value of the given input
* @param val Input value to look up the value of
* @return The value of the given input
*/
public function val(val:Number): Number
{
return this.table[ int(val*this.pow) ];
}
/**
* Look up the value of the given number of radians
* @param radians Radians to look up the value of
* @return The value of the given number of radians
*/
public function valTrig(radians:Number): Number
{
return radians >= 0
? this.table[int((radians%this.TWO_PI)*this.pow)]
: this.table[int((TWO_PI+radians%this.TWO_PI)*this.pow)];
}
/**
* Look up the value of the given number of radians
* @param radians Radians to look up the value of. Must be positive.
* @return The sine of the given number of radians
* @throws RangeError If radians is not positive
*/
public function valTrigPositive(radians:Number): Number
{
return this.table[int((radians%this.TWO_PI)*this.pow)];
}
/**
* Look up the value of the given number of radians
* @param radians Radians to look up the value of. Must be on (-2pi,2pi).
* @return The value of the given number of radians
* @throws RangeError If radians is not on (-2pi,2pi)
*/
public function valTrigNormalized(radians:Number): Number
{
return radians >= 0
? this.table[int(radians*this.pow)]
: this.table[int((this.TWO_PI+radians)*this.pow)];
}
/**
* Look up the value of the given number of radians
* @param radians Radians to look up the value of. Must be on [0,2pi).
* @return The value of the given number of radians
* @throws RangeError If radians is not on [0,2pi)
*/
public function valTrigNormalizedPositive(radians:Number): Number
{
return this.table[int(radians*this.pow)];
}
}