Latest snippets

globalToLocal() in 3D

[SWF(frameRate=60, backgroundColor=0x000000, width=500, height=500)]
stage.quality = "medium";
var frame:Sprite = Sprite(addChild(new Sprite()));
with (frame.graphics) beginFill(0xCCCCCC), drawRect(-200, -200, 400, 400), endFill();
frame.x = stage.stageWidth / 2;
frame.y = stage.stageHeight / 2;
frame.z = 100;

var canvas:Shape = Shape(frame.addChild(new Shape()));
var msk:Shape = Shape(frame.addChild(new Shape()));
with (msk.graphics) beginFill(0x00FF00), drawRect(-200, -200, 400, 400), endFill();
canvas.mask = msk

var txt:TextField = TextField(addChild(new TextField()));
txt.defaultTextFormat = new TextFormat("_sans", 12);
txt.x = txt.y = 10;
txt.textColor = 0xFFFFFF, txt.autoSize="left", txt.text = "Draw on the 3D plane...";

stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
function onDown(evt:MouseEvent):void{
	canvas.graphics.lineStyle(4, 0x000000);
	var pnt:Point = frame.globalToLocal(new Point(mouseX, mouseY));
	canvas.graphics.moveTo(pnt.x, pnt.y);
	addEventListener(Event.ENTER_FRAME, onDraw);
}
function onUp(evt:MouseEvent):void{
	removeEventListener(Event.ENTER_FRAME, onDraw);
}

var t:Number = 0;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
    frame.rotationY = 35 * Math.sin(t);
	frame.rotationX = 35 * Math.cos(t);
	t+=0.02;
}

function onDraw(evt:Event):void {
        var pnt:Point = frame.globalToLocal(new Point(mouseX, mouseY));
	canvas.graphics.lineTo(pnt.x, pnt.y);
}

This demo shows that globalToLocal() works with 3D – saving us the trouble of doing some extra math if we want to draw on 3D display objects…

Have a look at the swf….


Was made aware of this trick by watching a video that kevinSuttle sent me via twitter. The video is an interview with Chris Nuuja (one of the flash player engineers).

3D Key Controls

[SWF(backgroundColor=0x000000, width=500, height=500)]
var hsw:Number = stage.stageWidth / 2;
var hsh:Number = stage.stageHeight / 2;
var pointNum:int = 300;
var points3D:Vector.<Number> = new Vector.<Number>();
var points2D:Vector.<Number> = new Vector.<Number>();
var uvts:Vector.<Number> = new Vector.<Number>();
var sorted:Array = [];
var pnt:Point = new Point();
var m:Matrix3D = new Matrix3D();
var v:Vector3D = new Vector3D();
for (var i:int = 0; i<pointNum; i++){
	v.x = 300;
	v.y = v.z = 0;
	m.identity();
	m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
	m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
	m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
	v = m.transformVector(v);
	points3D.push(v.x, v.y, v.z);
	points2D.push(0,0);
	uvts.push(0,0,0);
	sorted.push(new Vector3D());
}
points3D.fixed = true;
points2D.fixed = true;
uvts.fixed = true;
var p:PerspectiveProjection = new PerspectiveProjection();
var proj:Matrix3D = p.toMatrix3D();
var rx:Number = 0, ry:Number = 0;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	var i:int, j:int;
	m.identity();
	if (key[Keyboard.RIGHT]){
		rx+=3
	}else
	if (key[Keyboard.LEFT]){
		rx-=3
	}else
	if (key[Keyboard.UP]){
		ry-=3
	}else
	if (key[Keyboard.DOWN]){
		ry+=3
	}
	m.appendRotation(rx, Vector3D.Y_AXIS);
	m.appendRotation(ry, Vector3D.X_AXIS);
	m.appendTranslation(0, 0, 1000);
	m.append(proj);
	Utils3D.projectVectors(m, points3D, points2D, uvts);
	for (i = 0, j = 0; i<points2D.length; i+=2, j++){
		sorted[j].x = points2D[i] + hsw;
		sorted[j].y = points2D[i + 1] + hsh;
		sorted[j].z = uvts[j * 3 + 2];
	}
	sorted.sortOn("z", Array.NUMERIC);
	graphics.clear();
	graphics.lineStyle(2, 0x000000, 0.1);
	for(i = 0; i<sorted.length; i++){
		var zpos:Number = sorted[i].z * 12000;
		var c:int = zpos * 14;
		c = (c > 255) ? 255 : c;
		graphics.beginFill(100<<16 | 100 << 8 |c);
		graphics.drawCircle(sorted[i].x, sorted[i].y,zpos);
		graphics.endFill();
	}
}

// permanently applies the matrix to the points3D vector
function applyTransform():void{
	m.identity();
	m.appendRotation(rx, Vector3D.Y_AXIS);
	m.appendRotation(ry, Vector3D.X_AXIS);
	var temp:Vector.<Number> = new Vector.<Number>();
	m.transformVectors(points3D, temp);
	points3D = temp;
	points3D.fixed = true;
	rx = 0, ry = 0;
}

// basic key setup
var key:Object = new Object();
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyReleased);
function onKeyPressed(evt:KeyboardEvent):void {
	key[evt.keyCode] = true;
	key.keyCode = evt.keyCode;
}
function onKeyReleased(evt:KeyboardEvent):void { 
  applyTransform();
  key[evt.keyCode] = false;
}

In response to Thomas Francis’s question, this snippet takes the Simple z-sorting snippet and shows how one might go about adding some basic key controls to it. It works by permanently applying x and y rotation transformations to the set of 3D points every time a key is released.

Check out the swf…

If you need to be able to rotate on both the x and y axis at the same time – and just need more flexibility… one way to do it would be to use quaternions – which may be tricky – but there are plenty of examples out there in java, processing and C/C++ just waiting to be ported (been on the todo list for some time actually).

Haven’t been posting every day because I’ve been out of the country and away from my computer… have a backlog of snippets that need to be cleaned up and put in the pipeline…

Simple z-sorting

[SWF(backgroundColor=0x444444, width=500, height=500)]
var hsw:Number = stage.stageWidth / 2;
var hsh:Number = stage.stageHeight / 2;

var pointNum:int = 200;
var points3D:Vector.<Number> = new Vector.<Number>();
var points2D:Vector.<Number> = new Vector.<Number>();
var uvts:Vector.<Number> = new Vector.<Number>();
var sorted:Array = [];

var pnt:Point = new Point();
var m:Matrix3D = new Matrix3D();
var v:Vector3D = new Vector3D();
for (var i:int = 0; i<pointNum; i++){
	v.x = Math.random()*400-200;
	m.identity();
	m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
	m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
	m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
	v = m.transformVector(v);
	points3D.push(v.x, v.y, v.z);
	points2D.push(0,0);
	uvts.push(0,0,0);
	sorted.push(new Vector3D());
}
points3D.fixed = true;
points2D.fixed = true;
uvts.fixed = true;

var p:PerspectiveProjection = new PerspectiveProjection();
var proj:Matrix3D = p.toMatrix3D();

var dx:Number = 0, dy:Number = 0;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	var i:int, j:int;
	dx += (mouseX - dx) / 4;
	dy += (mouseY - dy) / 4;
	m.identity();
	m.appendRotation(dx, Vector3D.Y_AXIS);
	m.appendRotation(dy, Vector3D.X_AXIS);
	m.appendTranslation(0, 0, 1000);
	m.append(proj);
	
	Utils3D.projectVectors(m, points3D, points2D, uvts);
	
	for (i = 0, j = 0; i<points2D.length; i+=2, j++){
		sorted[j].x = points2D[i] + hsw;
		sorted[j].y = points2D[i + 1] + hsh;
		sorted[j].z = uvts[j * 3 + 2];
	}
	sorted.sortOn("z", Array.NUMERIC);
	
	graphics.clear();
	for(i = 0; i<sorted.length; i++){
		var zpos:Number = sorted[i].z * 12000;
		var c:int = zpos * 14;
		graphics.beginFill(c << 16 | c << 8 | c);
		graphics.drawCircle(sorted[i].x, sorted[i].y,zpos);
		graphics.endFill();
	}
}

Here is an easy way to do z-sorting on a cluster of circles.


Have a look at the swf over at wonderfl…

BitmapData Static

var canvas:BitmapData = new BitmapData(500,500,false, 0x000000);
addChild(new Bitmap(canvas));

var pix:Vector.<uint> = new Vector.<uint>(canvas.width * canvas.height, true);

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	canvas.lock();
	var i:int = pix.length;
	while(--i > -1){
		var c:uint = uint(Math.random() * 255);
	    pix[i] = c << 16 | c << 8 | c;
	}
	canvas.setVector(canvas.rect, pix);
	canvas.unlock();
}

This is an easy way to fill a BitmapData Object up with a bunch of TV-style static….

This post is meant to serve as filler while I work to get a good solid SIMPLE fp10, drawing api z-sorting example going… There seem to be 3 main ways of doing z-sorting all of which don’t seem right to me for some reason… they all work… but I have a gut feeling there is a faster way… The winner so far (unexpectedly) is using Array.sortOn

Gradient Bezier 3D

[SWF(backgroundColor=0x333333, width=800, height=600)];
x = stage.stageWidth / 2;
y = stage.stageHeight / 2;
var verts:Vector.<Number>  = new Vector.<Number>();
var tVerts:Vector.<Number> = new Vector.<Number>();
var pVerts:Vector.<Number> = new Vector.<Number>();
var uvts:Vector.<Number> = new Vector.<Number>();

var igraph:Vector.<IGraphicsData> = new Vector.<IGraphicsData>();

var tVect:Vector3D = new Vector3D();
var m:Matrix3D = new Matrix3D();
for (var i:int = 0; i<200; i++){
	for (var j:int = 0; j<3; j++){
		tVect.x = Math.random() * 0.15;
		m.identity();
		m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
		m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
		m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
		tVect = m.transformVector(tVect);
	    verts.push(tVect.x, tVect.y, tVect.z);
	}
	
	var stroke:GraphicsStroke = new GraphicsStroke();
	
	var col:int = [0xFFFFFF, 0x000000, 0xFFCC00, 0xFF0000][int(Math.random() * 4)];
	
    stroke.thickness = 2+(Math.random()*Math.random())*8;
	var mg:Matrix = new Matrix();
	mg.createGradientBox(350+Math.random()*20-10, 350+Math.random()*20-10, 0, -270+i/2,-240+i/2);
	stroke.fill = new GraphicsGradientFill(GradientType.RADIAL, [0xFFFFFF,0x444444], [1, 1], [30, 255], mg);

	var bez:GraphicsPath = new GraphicsPath();
	bez.commands = Vector.<int>([1, 3]);
	igraph.push(stroke);
    igraph.push(bez);
}

var perspective:PerspectiveProjection = new PerspectiveProjection();
perspective.fieldOfView = 45;
var trans:Matrix3D = new Matrix3D();
var proj:Matrix3D = perspective.toMatrix3D();
var dx:Number = 0, dy:Number = 0;

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	dx += (mouseX - dx) / 4;
	dy += (mouseY - dy) / 4;
	   
	trans.identity();
	trans.appendRotation(dy, Vector3D.X_AXIS);
	trans.appendRotation(dx, Vector3D.Y_AXIS);
	trans.appendTranslation(0,0,0.5);
	trans.transformVectors(verts, tVerts);
	Utils3D.projectVectors(proj, tVerts, pVerts, uvts);
	
	var inc:int = 0;
	for (var i:int = 1; i<igraph.length; i+=2){
		GraphicsPath(igraph[i]).data = pVerts.slice(inc, inc + 6);
		inc += 6;
	}
	 
	graphics.clear();
	graphics.drawGraphicsData(igraph);
}

A variation on yesterdays post – this makes use of GraphicsGradientFill to add some depth…

Check out the swf…

3D Bezier

[SWF(backgroundColor=0x000000, width=800, height=600)];
x = stage.stageWidth / 2;
y = stage.stageHeight / 2;
var verts:Vector.<Number>  = new Vector.<Number>();
var tVerts:Vector.<Number> = new Vector.<Number>();
var pVerts:Vector.<Number> = new Vector.<Number>();
var uvts:Vector.<Number> = new Vector.<Number>();

var igraph:Vector.<IGraphicsData> = new Vector.<IGraphicsData>();

var tVect:Vector3D = new Vector3D();
var m:Matrix3D = new Matrix3D();
for (var i:int = 0; i<300; i++){
	for (var j:int = 0; j<3; j++){
		tVect.x = Math.random() * 0.15;
		m.identity();
		m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
		m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
		m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
		tVect = m.transformVector(tVect);
	    verts.push(tVect.x, tVect.y, tVect.z);
	}
	
	 
	var stroke:IGraphicsData = new GraphicsStroke();
	
	var col:int = [0xFFFFFF, 0x000000, 0xFFCC00, 0xFF0000][int(Math.random() * 4)];
    with (stroke) thickness = (Math.random()*Math.random())*10, fill = new GraphicsSolidFill(col);

	var bez:GraphicsPath = new GraphicsPath();
	bez.commands = Vector.<int>([1, 3]);
	igraph.push(stroke);
    igraph.push(bez);
}

var perspective:PerspectiveProjection = new PerspectiveProjection();
perspective.fieldOfView = 45;
var trans:Matrix3D = new Matrix3D();
var proj:Matrix3D = perspective.toMatrix3D();
var dx:Number = 0, dy:Number = 0;

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	dx += (mouseX - dx) / 4;
	dy += (mouseY - dy) / 4;
	   
	trans.identity();
	trans.appendRotation(dy, Vector3D.X_AXIS);
	trans.appendRotation(dx, Vector3D.Y_AXIS);
	trans.appendTranslation(0,0,0.5);
	trans.transformVectors(verts, tVerts);
	Utils3D.projectVectors(proj, tVerts, pVerts, uvts);
	
	var inc:int = 0;
	for (var i:int = 1; i<igraph.length; i+=2){
		GraphicsPath(igraph[i]).data = pVerts.slice(inc, inc + 6);
		inc += 6;
	}
	 
	graphics.clear();
	graphics.drawGraphicsData(igraph);
}

After a few hours of trying to get a super optimized fp10 z-sorting demo happening, I gave up (for now) and decided to just let loose with something easy. The result is this 3D Bezier example…


Check out the swf…

Sierpiński Glitch Texture #3

[SWF(frameRate=60, backgroundColor=0x000000, width=500, height=500)]
 
var canvas:BitmapData = new BitmapData(500,500,false, 0x000000);
addChild(new Bitmap(canvas));
var clone:BitmapData = new BitmapData(500,500,false, 0x000000);
var canvasRect:Rectangle = canvas.rect;
var w:int = canvas.width;
var w2:Number = 1/w;
var w10:Number = 1/(w * 80);
var convert:Number = Math.PI/180;
var size:int = canvas.width * canvas.height;
var pix:Vector.<uint> = new Vector.<uint>(size, true);
var m:Matrix = new Matrix();
m.scale(1,-1);
m.translate(0,canvas.height);
var sin:Number = 0, cos:Number = 0;
var dx:Number = 0, dy:Number = 0;
var pnt:Point = new Point();
var blur:BlurFilter = new BlurFilter(10,10,1);
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	canvas.lock();
	dx +=  (mouseX * 10 - 3000 - dx) / 8;
	dy +=  (mouseY * 4 - dy) / 8;
	for (var i:int = 0; i<size; i++){
		var xp:int = i % w;
		var yp:int = int(i * w2);
		var xp2:int = xp <<1;
		var t:Number;
		t = ((yp|(xp + yp * 0.1)) * (xp + dx) *w10) % 6.14687;
		//compute sine
		// technique from http://lab.polygonal.de/2007/07/18/fast-and-accurate-sinecosine-approximation/
		// by Michael Baczynski
		if (t<0) {
			sin=1.27323954*t+.405284735*t*t;
		} else {
			sin=1.27323954*t-0.405284735*t*t;
		}
		// compute cosine
		t = (xp2|(yp+xp*0.1) + dy) * convert % 6.28;
		t+=1.57079632;
		if (t>3.14159265) {
			t-=6.28318531;
		}
		if (t<0) {
			cos=1.27323954*t+0.405284735*t*t;
		} else {
			cos=1.27323954*t-0.405284735*t*t;
		}
		var c1:int = 31 * (sin - cos);
		if (c1 <0) c1 = 256 - c1;
		c1 = (c1 <<4 | c1) ;
		pix[i] = c1 <<16 | c1 <<8 | c1;
	}
	canvas.setVector(canvasRect, pix);
	clone.copyPixels(canvas, canvasRect, pnt);
	canvas.draw(clone, m, null, BlendMode.SUBTRACT);
	clone.copyPixels(canvas, canvasRect, pnt);
	clone.applyFilter(clone, canvasRect, pnt, blur);
	canvas.draw(clone, null, null, BlendMode.SCREEN);
	canvas.unlock();
}

Decided to do a grayscale version … also rendered it out large and posted it on flickr…

Check out the swf…


Check out the large flickr version…

Sierpiński Glitch Texture #2

[SWF(frameRate=60, backgroundColor=0x000000, width=500, height=500)]
var canvas:BitmapData = new BitmapData(500,500,false, 0x000000);
addChild(new Bitmap(canvas));
var clone:BitmapData = new BitmapData(500,500,false, 0x000000);
var canvasRect:Rectangle = canvas.rect;
var w:int = canvas.width;
var w2:Number = 1/w;
var w10:Number = 1/(w * 80);
var convert:Number = Math.PI/180;
var size:int = canvas.width * canvas.height;
var pix:Vector.<uint> = new Vector.<uint>(size, true);
var gray:ColorMatrixFilter = new ColorMatrixFilter([1, 0.55, 0.55, 0,0,0.55, 0.9, 0.55, 0,0,0.55, 0.55, 0.550,0, 0,0,0,1,0]);
var m:Matrix = new Matrix();
m.scale(1,-1);
m.translate(0,canvas.height);
var sin:Number = 0, cos:Number = 0;
var dx:Number = 0, dy:Number = 0;
var pnt:Point = new Point();
var blur:BlurFilter = new BlurFilter(10,10,1);
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	canvas.lock();
	dx += (mouseX * 10 - 3000 - dx) / 8;
	dy += (mouseY * 4 - dy) / 8;
	for (var i:int = 0; i<size; i++){
		var xp:int = i % w;
		var yp:int = int(i * w2);
		var xp2:int = xp <<1;
		var t:Number;
		t = ((yp|(xp + yp)) * (xp + dx) *w10) % 6.14687;
		//compute sine
		// technique from http://lab.polygonal.de/2007/07/18/fast-and-accurate-sinecosine-approximation/
		// by Michael Baczynski
		if (t<0) {
			sin=1.27323954*t+.405284735*t*t;
		} else {
			sin=1.27323954*t-0.405284735*t*t;
		}
		// compute cosine
		t = (xp2|(yp+xp/dx) + dy) * convert % 6.28;
		t+=1.57079632;
		if (t>3.14159265) {
			t-=6.28318531;
		}
		if (t<0) {
			cos=1.27323954*t+0.405284735*t*t;
		} else {
			cos=1.27323954*t-0.405284735*t*t;
		}
		var c1:int = 31 * (sin - cos);
		if (c1 <0) c1 = 256 - c1;
		c1 = (c1 >>1  | c1) ;
		pix[i] = c1 <<17 | c1 <<8 | c1;
	}
	canvas.setVector(canvasRect, pix);
	clone.copyPixels(canvas, canvasRect, pnt);
	canvas.draw(clone, m, null, BlendMode.SUBTRACT);
	clone.copyPixels(canvas, canvasRect, pnt);
	clone.applyFilter(clone, canvasRect, pnt, blur);
	
	canvas.draw(clone, null, null, BlendMode.LIGHTEN);
	canvas.applyFilter(canvas, canvasRect, pnt, gray);
	canvas.unlock();
}

More texture experimentation…

Have a look at the swf over at wonderfl.net…

Sierpiński Glitch Texture #1

[SWF(frameRate=60, backgroundColor=0x000000, width=500, height=500)]
var canvas:BitmapData = new BitmapData(500,500,false, 0x000000);
addChild(new Bitmap(canvas));
var clone:BitmapData = new BitmapData(500,500,false, 0x000000);
var canvasRect:Rectangle = canvas.rect;
var w:int = canvas.width;
var w2:Number = 1/w;
var w10:Number = 1/(w * 80);
var convert:Number = Math.PI/180;
var size:int = canvas.width * canvas.height;
var pix:Vector.<uint> = new Vector.<uint>(size, true);
var gray:ColorMatrixFilter = new ColorMatrixFilter([1, 0.55, 0.55, 0,0,0.55, 0.9, 0.55, 0,0,0.55, 0.55, 0.550,0, 0,0,0,1,0]);
var m:Matrix = new Matrix();
m.scale(1,-1);
m.translate(0,canvas.height);
var sin:Number = 0, cos:Number = 0;
var dx:Number = 0, dy:Number = 0;
var pnt:Point = new Point();
var blur:BlurFilter = new BlurFilter(10,10,1);
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	canvas.lock();
	dx += (mouseX * 10 - 3000 - dx) / 8;
	dy += (mouseY * 4 - dy) / 8;
	for (var i:int = 0; i<size; i++){
		var xp:int = i % w;
		var yp:int = int(i * w2);
		var xp2:int = xp <<1;
		var t:Number;
		t = ((yp|xp) * (xp + dx) *w10) % 6.14687;
		
		//compute sine
		// technique from http://lab.polygonal.de/2007/07/18/fast-and-accurate-sinecosine-approximation/
		// by Michael Baczynski
		if (t<0) {
			sin=1.27323954*t+.405284735*t*t;
		} else {
			sin=1.27323954*t-0.405284735*t*t;
		}
		// compute cosine
		t = (xp2 + dy) * convert % 6.28;
		t+=1.57079632;
		if (t>3.14159265) {
			t-=6.28318531;
		}
		if (t<0) {
			cos=1.27323954*t+0.405284735*t*t;
		} else {
			cos=1.27323954*t-0.405284735*t*t;
		}
		var c1:int = 31 * (sin - cos);
		if (c1 <0) c1 = 256 - c1;
		c1 = (c1 <<3 | c1) ;
		pix[i] = c1 <<15 | c1 <<8 | c1;
	}
	canvas.setVector(canvasRect, pix);
	clone.copyPixels(canvas, canvasRect, pnt);
	canvas.draw(clone, m, null, BlendMode.SUBTRACT);
	clone.copyPixels(canvas, canvasRect, pnt);
	clone.applyFilter(clone, canvasRect, pnt, blur);
	canvas.draw(clone, null, null, BlendMode.ADD);
	canvas.unlock();
}

More strange real-time texture generation. This one is particularly glitchy looking with hints of Sierpiński.


Check out the swf at wonderfl.net…

Interesting Texture #3 (animated)

[SWF(frameRate=60, backgroundColor=0x000000, width=500, height=500)]
var canvas:BitmapData = new BitmapData(500,500,false, 0x000000);
addChild(new Bitmap(canvas));
var clone:BitmapData = new BitmapData(500,500,false, 0x000000);
var canvasRect:Rectangle = canvas.rect;
var w:int = canvas.width;
var w2:Number = 1/w;
var w10:Number = 1/(w * 80);
var convert:Number = Math.PI/180;
var size:int = canvas.width * canvas.height;
var pix:Vector.<uint> = new Vector.<uint>(size, true);
var gray:ColorMatrixFilter = new ColorMatrixFilter([1, 0.55, 0.55, 0,0,0.55, 0.9, 0.55, 0,0,0.55, 0.55, 0.550,0, 0,0,0,1,0]);
var m:Matrix = new Matrix();
m.scale(1,-1);
m.translate(0,canvas.height);
var sin:Number = 0, cos:Number = 0;
var dx:Number = 0, dy:Number = 0;
var pnt:Point = new Point();
var blur:BlurFilter = new BlurFilter(10,10,1);
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	canvas.lock();
	dx += (mouseX * 10 - 3000 - dx) / 8;
	dy += (mouseY * 4 - dy) / 8;
	for (var i:int = 0; i<size; i++){
		var xp:int = i % w;
		var yp:int = int(i * w2);
		var xp2:int = xp << 1;
		var t:Number = (yp * (xp2 + dx) * w10) % 3.14687;
		//compute sine
		// technique from http://lab.polygonal.de/2007/07/18/fast-and-accurate-sinecosine-approximation/
		// by Michael Baczynski
		if (t<0) {
			sin=1.27323954*t+.405284735*t*t;
		} else {
			sin=1.27323954*t-0.405284735*t*t;
		}
		// compute cosine
		t = (xp2 + dy) * convert % 6.28;
		t+=1.57079632;
		if (t>3.14159265) {
			t-=6.28318531;
		}
		if (t<0) {
			cos=1.27323954*t+0.405284735*t*t;
		} else {
			cos=1.27323954*t-0.405284735*t*t;
		}
		var c1:int = 31 * (cos - sin);
		if (c1 <0) c1 = 256 - c1;
		c1 = (c1 <<2 | c1) ;
		pix[i] = c1 <<15 | c1 <<9 | c1;
	}
	canvas.setVector(canvasRect, pix);
	clone.copyPixels(canvas, canvasRect, pnt);
	canvas.draw(clone, m, null, BlendMode.SUBTRACT);
	clone.copyPixels(canvas, canvasRect, pnt);
	clone.applyFilter(clone, canvasRect, pnt, blur);
	canvas.draw(clone, null, null, BlendMode.ADD);
	canvas.applyFilter(canvas, canvas.rect, new Point(0,0), gray);
	canvas.unlock();
}

This snippet creates an interactive animated texture. Originally this texture wasn an unoptimized messy code snippet (see the original post here) – I went through and did a few optimizations to get it running in real-time and this is the result:

Check out the swf over at wonderfl.net…