Browse the notebook

Category: pixel manipulation

Interesting Texture #3

var canvas:BitmapData = new BitmapData(1500,1000,false, 0x000000);
addChild(new Bitmap(canvas));
scaleX = scaleY = .5;

var w:int = canvas.width;
var w10:int = w * 80;
var convert:Number = Math.PI/180;
var size:int = canvas.width * canvas.height;
for (var i:int = 0; i<size; i++){
	var xp:int = i % w;
	var yp:int = int(i / w);
	var xp2:int = xp * 2;
	var c1:int = (255/8) * (Math.cos(xp2 * convert) - Math.sin(yp*(xp2 + 500)/w10));
	if (c1 < 0) c1 = 256 - c1;
	c1 = (c1 << 2 | c1) ;
	canvas.setPixel(xp, yp, c1 <<15 | c1 <<9 | c1 );
}
var m:Matrix = new Matrix();
m.scale(1,-1);
m.translate(0,canvas.height);
var clone:BitmapData = canvas.clone();
canvas.draw(clone, m, null, BlendMode.SUBTRACT);
clone.draw(canvas);
clone.applyFilter(clone, clone.rect, new Point(0,0), new BlurFilter(10,10,1));
canvas.draw(clone, null, null, BlendMode.ADD);
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]);
canvas.applyFilter(canvas, canvas.rect, new Point(0,0), gray);

Soon I’ll work on a real-time variation. For now, here is one more still…

Read snippet: Interesting Texture #3

Interesting Texture #2

var canvas:BitmapData = new BitmapData(1000,1000,false, 0x000000);
addChild(new Bitmap(canvas));
scaleX = scaleY = .5;

var w:int = canvas.width;
var w10:int = w * 40;
var size:int = canvas.width * canvas.height;
for (var i:int = 0; i<size; i++){
	var xp:int = i % w;
	 
	var yp:int = int(i / w);
	var c1:int = (255/8) * (Math.cos(xp* Math.PI/180 * 2) + Math.sin(yp*(xp + 200)/w10));
	if (c1 < 0) c1 = 256 - c1;
	c1 = (c1 << 1 | c1) ;
	canvas.setPixel(xp, yp, c1 <<15 | c1 <<7 | c1 );
}
var m:Matrix = new Matrix();
m.scale(1,-1);
m.translate(0,canvas.height);
var clone:BitmapData = canvas.clone();
canvas.draw(clone, m, null, BlendMode.SUBTRACT);
clone.draw(canvas);
clone.applyFilter(clone, clone.rect, new Point(0,0), new BlurFilter(10,10,1));
canvas.draw(clone, null, null, BlendMode.ADD);

Randomly bit shifting on this one is actually getting a good deal of millage.. I know I can easily optimize so that it works in realtime – could even be done in pixelbender… but going to play a bit more first before I optimize….

Read snippet: Interesting Texture #2

Interesting Texture

var canvas:BitmapData = new BitmapData(1000,1000,false, 0x000000);
addChild(new Bitmap(canvas));
scaleX = scaleY = .5;

var w:int = canvas.width;
var w10:int = w * 60;
var size:int = canvas.width * canvas.height;
for (var i:int = 0; i<size; i++){
	var xp:int = i % w;
	 
	var yp:int = int(i / w);
	var c1:int = (255/8) * (Math.cos(xp* Math.PI/180 * 2) + Math.sin(yp*yp/w10));
	if (c1 < 0) c1 = 256 - c1;
	c1 = (c1 << 1 | c1) ;
	canvas.setPixel(xp, yp, c1 <<16 | c1 <<8 | c1 );
}
var m:Matrix = new Matrix();
m.scale(1,-1);
m.translate(0,canvas.height);
var clone:BitmapData = canvas.clone();
canvas.draw(clone, m, null, BlendMode.SUBTRACT);
clone.draw(canvas);
clone.applyFilter(clone, clone.rect, new Point(0,0), new BlurFilter(10,10,1));
canvas.draw(clone, null, null, BlendMode.ADD);

Having one of those days where everything I code doesn’t look right to me… took a little break from other work and created this very unoptimized abstract texture… no animation so here is a bitmap:

Read snippet: Interesting Texture

Perlin Outlines

[SWF(width = 600, height=600, backgroundColor=0xCCCCCC, frameRate=24)]
var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight, false, 0x000000);
var blur:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight, false, 0x000000);
addChild(new Bitmap(canvas, "auto", true));

var w:int = canvas.width 
var hw:int = w / 2;
var size:int = w * w;
var seed:Number = Math.random()*100;
var pnt:Point = new Point();
var dy:Number = 0, dx:Number = 0;
var blr:BlurFilter = new BlurFilter(10,10,1);
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	
	dx += (mouseX - dx) / 4;
	dy += (mouseY - dy) / 4;
	canvas.lock();
	canvas.perlinNoise(hw,hw,2,seed,false, false, 1, true, [new Point(dx, dy), new Point(-dx, -dy)]);
	var pix:Vector.<uint> = canvas.getVector(canvas.rect);
	for (var i:int = 0; i<size; i++){
		var col:uint = 255 - pix[i] << 4 & 0x00FF00;
		pix[i] = col << 8 | col | col >> 8;
	}
	canvas.setVector(canvas.rect, pix);
	blur.copyPixels(canvas, canvas.rect, pnt);
	blur.applyFilter(blur, blur.rect, pnt, blr);
	canvas.draw(blur, null, null, BlendMode.DIFFERENCE);
	canvas.draw(canvas, null, null, BlendMode.INVERT);
	canvas.unlock();
}

This is actually an optimized variation on some recent posts that made use of perlin noise. You can get a wide range of effects by changing just the BlendMode values alone…. I particularly like this combination of BlendModes because it reminds me a bit of a terrain map…

Have a look at the swf…

Read snippet: Perlin Outlines

Another Perlin Texture

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

scaleX = scaleY = 0.5;
var w:int = canvas.width 
var hw:int = w / 2;
var hhw:int = hw / 2;
var size:int = canvas.width * canvas.width;

canvas.perlinNoise(hhw,hhw,1,Math.random()*100,false, false, 1, true);

for (var i:int = 0; i<size; i++){
	var xp:int = i % w;
	var yp:int = int(i / w);
	var col:uint =  canvas.getPixel(xp, yp) / (-20|i+xp) >> 8 & 0xFF
	canvas.setPixel(xp, yp, col << 16 | col << 8 | col);
}

canvas.applyFilter(canvas, canvas.rect, new Point(0,0), new BlurFilter(4,4,1));
var blur:BitmapData = canvas.clone();
blur.applyFilter(blur, blur.rect, new Point(0,0), new BlurFilter(10,10,1));

canvas.draw(blur, null, null, BlendMode.DARKEN);

This is a variation on yesterdays post. I think it’s time to optimize this and see how it does in real time…

Here is what this snippet will draw:

Read snippet: Another Perlin Texture

drawTriangles() Terrain

[SWF(width=500,height=500,backgroundColor=0x333333, frameRate=40)]
var terrain:Shape = Shape(addChild(new Shape()));
terrain.x = terrain.y = 250;
var rows:int = 60;
var size:int = rows + 1;
var vertNum:int = size * size;
var polySize:Number = 5;
var gridWidth:Number = polySize * rows;
var halfWidth:Number = gridWidth / 2;
var verts:Vector.<Number> = new Vector.<Number>();
var pVerts:Vector.<Number> = new Vector.<Number>();
var indices:Vector.<int> = new Vector.<int>();
var uvs:Vector.<Number> = new Vector.<Number>();
var uvts:Vector.<Number> = new Vector.<Number>();
var tex:BitmapData = new BitmapData(gridWidth, gridWidth, false, 0x000000);
var pix:int = gridWidth * gridWidth;
var perlin:BitmapData = new BitmapData(gridWidth, gridWidth, false, 0x000000);
// generate the texture and the terrain
function generate():void{
	tex.fillRect(tex.rect, 0x000000);
	var i:Number, xp:Number, yp:Number;
	for (i = 0; i<pix; i++){
		xp = i % gridWidth;
		yp= int(i / gridWidth);
		var dx:Number = xp - gridWidth / 2;
		var dy:Number = yp - gridWidth / 2;
		var d:Number = 255 - Math.sqrt(dx * dx + dy * dy) / halfWidth* 255;
		if (d <0) d = 0;
		if (d> 255) d = 255;
		var c:uint = uint(d);
		tex.setPixel(xp, yp, c <<16 | c <<8 | c);
	}
	perlin.perlinNoise(100,100,3,Math.random()*100,false,false,7,true);
	perlin.draw(perlin, null, null, BlendMode.SCREEN);
	tex.draw(perlin, null, null, BlendMode.MULTIPLY);
	// calculate verts, uvs and indices
	var vIndex:int = 0;
	var uvIndex:int = 0;
	indices = new Vector.<int>();
	for (i = 0; i<vertNum; i++){
		var xMod:Number = i % size;
		xp = xMod * polySize;
		yp = int(i / size) * polySize;
		verts[vIndex++] = xp - halfWidth;
		verts[vIndex++] = yp - halfWidth;
		verts[vIndex++] = tex.getPixel(xp, yp) & 0xFF;
		uvs[uvIndex++] = xp /  gridWidth;
		uvs[uvIndex++] = yp / gridWidth;
		if (xMod != rows){
			  indices.push(i, i+1, i+size, i+1, i+size+1, i+size);
		}
	}
}
generate();
stage.addEventListener(MouseEvent.MOUSE_DOWN, onGenerate);
function onGenerate(evt:MouseEvent):void{ generate() };
var m:Matrix3D = new Matrix3D();
var rot:Number = 0;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
		m.identity();
		var destRot:Number = mouseX / stage.stageWidth * 90;
		if (destRot <0) destRot = 0;
		if (destRot> 90) destRot = 90;
		rot += (destRot - rot) * 0.2;
		m.appendRotation(rot,Vector3D.Z_AXIS);
		m.appendRotation(60,Vector3D.X_AXIS);
		Utils3D.projectVectors(m, verts, pVerts, uvts);
		with(terrain.graphics){
			clear();
			beginBitmapFill(tex, null, false, true);
			drawTriangles(pVerts, indices, uvs, TriangleCulling.NEGATIVE);
		}
}

This snippet draws a pretty simple isometric terrain using fp10 graphics stuff and perlin noise.


Have a look at the swf here…

Read snippet: drawTriangles() Terrain

setVector() CA Texture

[SWF(width=500, height=500)]
var canvasSize:int=stage.stageWidth;
var canvas:BitmapData=new BitmapData(canvasSize,canvasSize,false,0x000001);
addChild(new Bitmap(canvas, "auto", true));
var size:int=canvas.width*canvas.height - canvasSize;
var pixels:Vector.<uint>=canvas.getVector(canvas.rect);
for (var i:int = 0; i<canvasSize; i++) {
	var xp:int=int(Math.random()*canvasSize);
	var yp:int=int(Math.random()*canvasSize);
	pixels[xp+yp*canvasSize]=0xFF000000;
}
var targetCol:uint=0xFF000000;
var buffer:Vector.<uint>=pixels.concat();
var fade:uint=1;

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	var curr:uint=targetCol;
	var r:int = (curr >> 16) & 0xFF;
	var g:int = (curr >> 8) & 0xFF;
	var b:int=curr&0xFF;
	r+=fade;
	g+=fade;
	b+=fade;
	if (r>255) r=255;
	if (g>255) g=255;
	if (b>255) b=255;
	var darker:uint=0xFF000000|r<<16|g<<8|b;
	if (darker==0xFFFFFFFF) {
		removeEventListener(Event.ENTER_FRAME, onLoop);
	}
	for (var i:int = canvasSize; i<size; i++) {
		curr=pixels[i];
		if (curr==targetCol) {
			var index:int=i-canvasSize+int(Math.random()*3) - 1;
			if (index>0) buffer[index]=darker;
			if (int(Math.random()*50)==1) {
				index=i-canvasSize+int(Math.random()*3)-1;
				if (index>0) buffer[index]=darker;
			}
		}
	}
	targetCol=darker;
	canvas.lock();
	canvas.setVector(canvas.rect, buffer);
	pixels=buffer.concat();
	canvas.unlock();
}

This snippet uses setVector() to draw something that looks like this:

This is a cellular automaton. It has kind of a strange rule set – but you could easily use this snippet to do more traditional cellular automata.

Read snippet: setVector() CA Texture

Bresenham’s Circle and setVector()

var canvasSize:int = 400;
var canvas:BitmapData = new BitmapData(canvasSize, canvasSize, false, 0xFFFFFF);
addChild(new Bitmap(canvas));
var size:int = canvas.width * canvas.height;
var pixels:Vector.<uint> = canvas.getVector(canvas.rect);

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	 for (var i:int = 0; i<500; i++){
	  fillCircle(int(Math.random() * canvasSize),
					  int(Math.random() * canvasSize),
					  int(Math.random() * 5 + 3),
					  uint(Math.random() * 0xFFFF));
	 }
	 canvas.lock();
	 canvas.setVector(canvas.rect, pixels);
	 canvas.unlock();
}

function fillCircle(xp:int,yp:int, radius:int, col:uint = 0x000000):void {
	var xoff:int =0;
	var yoff:int = radius;
	var balance:int = -radius;
	while (xoff <= yoff) {
		 var p0:int = xp - xoff;
		 var p1:int = xp - yoff;
		 var w0:int = xoff + xoff;
		 var w1:int = yoff + yoff;
		 hLine(p0, yp + yoff, w0, col);
		 hLine(p0, yp - yoff, w0, col);
		 hLine(p1, yp + xoff, w1, col);
		 hLine(p1, yp - xoff, w1, col);
		if ((balance += xoff++ + xoff)>= 0) {
			balance-=--yoff+yoff;
		}
	}
}
function hLine(xp:int, yp:int, w:int, col:uint):void {
	var index:int = xp + yp * canvasSize;
	for (var i:int = 0; i <w; i++){
		index++;
		if (index > -1 && index < size){
		  pixels[index] = col;
		}
	}
}

In the past I’ve posted examples of Bresenham’s Circle (here and here). Both of those examples make use of setPixel(). Today’s snippet demos a version of Bresenham’s Circle that works with setVector().

Read snippet: Bresenham’s Circle and setVector()

x and y Coordinates in 1D Array / Vector

var canvas:BitmapData=new BitmapData(400,400,false,0x000000);
addChild(new Bitmap(canvas));
var pix:Vector.<uint>=canvas.getVector(canvas.rect);

canvas.lock();
for (var i:int = 0; i<300; i++) {
	var xp:int=50+i;
	var yp:int=50+i/2;
	// target x and y coords in 1D array
	pix[xp+yp*400]=0xFFFFFF;
}
canvas.setVector(canvas.rect, pix);
canvas.unlock();

This snippet shows how to target x and y coordinates in a 1D Array / Vector. This can be useful sometimes when working with setVector().

This is sort of like re-inventing setPixel()…. and for that reason is kind of pointless – that said, it’s interesting to know. I first learned about this technique from using processing.

Read snippet: x and y Coordinates in 1D Array / Vector

sine cosine Gradient

[SWF(width=600,height=500,frameRate=30)]
var canvas:BitmapData=new BitmapData(600,500,false,0x000000);
addChild(new Bitmap(canvas));
var size:Number=canvas.width*canvas.height;
var w:Number=canvas.width;
var wd:Number=1/w;
var pix:Vector.<uint> = new Vector.<uint>();
var sin:Number;
var cos:Number;
var dx:Number=110;
var dy:Number=52;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	dx+=0.001;
	canvas.lock();
	for (var i:int = 0; i<size; i++) {
		var xp:Number=i%w;
		var yp:Number=int(i*wd);
		var xx:Number=xp*0.05+dx;
		var yy:Number=yp*0.05+dy;
		var t:Number= (xx * yy) % 3.14159265;
		//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: sin(t + PI/2) = cos(t)
		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 c:Number=sin+cos*cos*cos;
		// fast math abs
		c=c<0? -c:c;
		c=c*140;
		// math max 255
		c=c>255?255:c;
		pix[i]=c<<16|c<<8|c;
	}
	canvas.setVector(canvas.rect, pix);
	canvas.unlock();
}

The above snippet will animate a gradient that looks like this:

Read snippet: sine cosine Gradient