Triangular kaleidoscope with perlinNoise
FP 10 required !
[SWF(width = 800, height = 780, backgroundColor = 0x101010, frameRate = 30)]
Triangular Kaleidoscope with perlinNoise
using graphics.drawTriangles()-method
and uv -coordinates for texture mapping
to create a triangular reflections
Petri Leskinen 15.1.2009 Espoo, Finland
http://pixelero.wordpress.com
package
{
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.TriangleCulling; // FP 10 required !
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.text.TextField;
import flash.geom.Point;
// [SWF(width = 800, height = 780, backgroundColor = 0x101010, frameRate = 30)]
/**
* Triangular Kaleidoscope with perlinNoise
*
* using graphics.drawTriangles()-method
* and uv -coordinates for texture mapping
* to create a triangular reflections
*
* Petri Leskinen 15.1.2009 Espoo, Finland
* http://pixelero.wordpress.com
*/
public class TriangularRegular extends Sprite
{
public var vertices:Vector.<Number> = new Vector.<Number>(), // x,y,z -coordinates
indices:Vector.<int> = new Vector.<int>(), // triangle mesh
uvtData:Vector.<Number> = new Vector.<Number>(),
points:Array;
public var bmd:NeonPerlinStripes;
public var size:Number = 180;
protected var running:Boolean = false, phase:Number = 0.0;
internal var i:int, j:int, tmp:Number;
internal const HALFSQRT3:Number = 0.866025403784438;
internal const D120:Number = 120.0 / 180.0 * Math.PI;
public function TriangularRegular ():void {
addEventListener(Event.ADDED_TO_STAGE, init);
}
protected function init(e:Event = null):void {
var po:Object;
var id:int = 0,xp:Number, yp:Number;
var triangs:Array = [], paths:Array = [], tr:Array;
var n:int = 3 + stage.stageWidth / size;
var m:int = 2+stage.stageHeight/size /HALFSQRT3;
var uvIndex:int;
vertices = new Vector.<Number>(); // x,y,z -coordinates
indices = new Vector.<int>(); // triangle mesh
uvtData = new Vector.<Number>();
points = [];
// fill the stage (with triangles
for (j = 0; j != m; j++) {
paths[j] = [];
yp = size*j *HALFSQRT3;
uvIndex = ((j & 1) == 0) ? 0 : 2;
for (i = 0; i != n; i++) {
xp = (i - 0.5 * (j & 1)) * size ;
po = { x: xp,
y: yp,
id: id++,
uvIndex: uvIndex };
paths[j].push(po);
points.push(po);
uvIndex= (uvIndex+2)%3; // repeats the serie 2 1 0 2 1 0 2 1 0
}
if (j != 0) {
triangulatePaths(paths[j - 1], paths[j], false, triangs);
}
}
for each( tr in triangs) indices.push(tr[0].id, tr[1].id, tr[2].id);
bmd = new NeonPerlinStripes(size, size);
stage.addEventListener(MouseEvent.CLICK, toggleAnimation);
toggleAnimation();
}
private function render(e:Event=null):void {
bmd.update();
phase += 0.03;
var uvIndices:Array = [ { u: 0.5+0.5*Math.cos(phase-D120), v:0.5+0.5*Math.sin(phase-D120) },
{ u: 0.5+0.5*Math.cos(phase), v:0.5+0.5*Math.sin(phase) },
{ u: 0.5+0.5*Math.cos(phase+D120), v:0.5+0.5*Math.sin(phase+D120) } ];
uvtData = new Vector.<Number>();
vertices = new Vector.<Number>();
for each(var po:Object in points) {
uvtData.push(uvIndices[po.uvIndex].u, uvIndices[po.uvIndex].v);
vertices.push(po.x, po.y);
}
graphics.clear();
// graphics.lineStyle(1.0, 0x808080, 1.0); // uncomment to see the grid
graphics.beginBitmapFill(
bmd,
null, // no matrix
true // = repeat
);
graphics.drawTriangles(vertices,
indices,
uvtData,
TriangleCulling.NONE);
graphics.endFill();
}
// generates a triangle strip between two arrays of points
private function triangulatePaths(path0:Array, path1:Array, closed:Boolean=false, triangles:Array =null):Array {
if (triangles==null) triangles = [];
var index0:int = 0,index1:int = 0, dist0:Number, dist1:Number;
var po0:* = path0[index0];
var po1:* = path1[index1];
// if 'closed' push the first point as last one as well
if (closed && path0.length > 1 && po0!=path0[path0.length-1] ) path0.push(po0);
if (closed && path1.length > 1 && po1!=path1[path1.length-1] ) path1.push(po1);
// choose the new triangle by a shorter diagonal
while (index0 < path0.length-1 && index1 < path1.length-1) {
dist0 = (tmp = po0.x - path1[index1 + 1].x) * tmp + (tmp = po0.y - path1[index1 + 1].y) * tmp;
dist1 = (tmp = po1.x - path0[index0 + 1].x) * tmp + (tmp = po1.y - path0[index0 + 1].y) * tmp;
triangles.push( [po0, po1, (dist0 < dist1) ? po1 = path1[++index1] : po0 = path0[++index0] ]);
}
// creates a fan of triangles if the other path's already ended
while (index0 +1 < path0.length) triangles.push( [po0, po1, po0=path0[++index0]]);
while (index1 +1 < path1.length) triangles.push( [po0, po1, po1=path1[++index1]]);
return triangles;
}
// a click will stop animation
private function toggleAnimation(e:MouseEvent = null):void {
if (running=(!running)) {
addEventListener(Event.ENTER_FRAME, render);
} else {
removeEventListener (Event.ENTER_FRAME, render);
}
}
}
}
// NeonPerlinStripes:
// subclass for a modified perlinNoise
import flash.display.BitmapData;
import flash.geom.ColorTransform;
import flash.geom.Point;
import flash.display.BlendMode;
import flash.geom.Vector3D;
import flash.events.Event;
class NeonPerlinStripes extends BitmapData {
public var offsets1:Array = [new Point(),new Point(),new Point()];
private var phaseAngle:Number = 0.0;
private static var edge128:ColorTransform = new ColorTransform(-1,-1,-1,1,255,255,255);
private static var d120:Number = 120/180*Math.PI;
public function NeonPerlinStripes(w:int, h:int) {
super(w,h,true,0x00);
update();
}
public function update(e:Event=null):void {
phaseAngle += 0.03;
var cs:Number = Math.cos(phaseAngle);
offsets1[0].x += 0.03;
offsets1[0].y += 0.03;
offsets1[1].y -= cs*0.4;
offsets1[2].x -= 0.7;
var scale:Number = 1.0;
perlinNoise(scale*this.width,scale*this.height,3,13,true,true,1+2+4,false,offsets1);
this.draw(this,
null,
edge128,
BlendMode.DARKEN );
var fA:Number = 5.0; // 16.0-0.0*cs;
var fB:Number = 255.0-128.0*fA; // fA*255+fB = 255
this.draw(this,
null,
new ColorTransform(fA,fA,fA,1.0,fB,fB,fB),
BlendMode.NORMAL );
this.draw(this,
null,
new ColorTransform(1.0+cs,
1.0+Math.cos(phaseAngle+d120),
1.0+Math.cos(phaseAngle-d120)
),
BlendMode.MULTIPLY );
}
}