Browse the notebook

Category: pixel manipulation

More Messy Code

var size:Number = 800;
var canvas:BitmapData = new BitmapData(size,size,false, 0x000000);
addChild(new Bitmap(canvas, "auto", true));

scaleX = scaleY = .5;
var pix:Number = size * size;
var scale:Number = 1/(size/3);

for (var i:Number = 0; i<pix; i++){
       var xp:Number = (i % size);
       var yp:Number = int(i / size);
	   var xt:Number = xp * scale;
	   var yt:Number = yp * scale;
       var ca:Number =  (Math.abs(Math.tan(yt) * Math.pow(Math.sin(xt),3)) * 100 ) % 155;
       var cb:Number =  (Math.abs(Math.tan(xt) * Math.pow(Math.sin(yt),3)) * 100)  % 155;
       ca|= cb;
       canvas.setPixel(xp, yp,  ca << 16 | ca << 8 | ca);
}

Another messy code snippet that I e-mailed to myself at some point…

Try replacing line 16 with some of these variations:

ca &= cb;
ca += cb;
ca -= cb;
ca ^= cb;
ca %= cb

Read snippet: More Messy Code

Distance Render

var verts:Vector.<Number> = new Vector.<Number>();
var pVerts:Vector.<Number> = new Vector.<Number>();
var uvts:Vector.<Number> = new Vector.<Number>();

var hs:Number = 2.3;
var step:Number = 0.04;

var tVerts:Vector.<Number> = new Vector.<Number>();
var rVerts:Vector.<Number> = new Vector.<Number>();
var matrix:Matrix3D = new Matrix3D();
matrix.identity();
matrix.appendRotation(45,Vector3D.Y_AXIS);
matrix.appendRotation(45,Vector3D.X_AXIS);
var inc:int = 0;
var i:Number, j:Number, k:Number;
i = hs;
while( i > -hs){
	j = hs;
	while(j > -hs){
		k = hs;
		while(k > -hs){
			tVerts[inc] = -i;
			inc++
			tVerts[inc] = -j;
			inc++
			tVerts[inc] = -k;
			inc++
			k -= step;
		}
		j -= step;
	}
	i -= step;
}

matrix.transformVectors(tVerts, rVerts);
 
var vinc:int = 0;
inc = 0
var R:Number = 1.5;
var r:Number = .5;
for (i= -hs; i<hs; i+=step){
	for (j = -hs; j<hs; j+=step){
		for (k = -hs; k<hs; k+=step){
			var vx:Number = rVerts[inc] ;
			inc++
			var vy:Number = rVerts[inc]  ;
			inc++
			var vz:Number=  rVerts[inc] ;
			inc++
			var s:Number = Math.pow(vx  * vx  + vy * vy + vz * vz + R*R - r * r, 2) - 4 * (R * R)*(vx * vx + vy * vy); 
			if (s <0 && s > -.5){ 
				verts[vinc] = (i * 50);
				vinc++
				verts[vinc] = (j * 50);
				vinc++
				verts[vinc] = (k * 50);
				vinc++
				  inc += int((hs - k) / step) * 3;
				  k = hs;
			 }
		}
	}
}

var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
addChild(new Bitmap(canvas));
render();
function render():void{
	matrix.identity();
    matrix.appendTranslation(200, 200, 0);
	Utils3D.projectVectors(matrix, verts, pVerts, uvts);
	canvas.lock();
	canvas.fillRect(canvas.rect, 0x000000);
	var inc:int = 2;
	var c:int = 0;
	var r:Rectangle = new Rectangle();
	r.width = r.height = 2;
	for (var i:int = 0; i<pVerts.length; i+=2){
		  r.x = pVerts[i];
		  r.y = pVerts[i + 1];
		  c = Math.max(0,100 - verts[inc]);
		  canvas.fillRect(r, c << 16 | c << 8 | c);
		  inc += 3; 
	}
	canvas.unlock();
}

This snippet uses some of the techniques from the last few posts to create a distance render – this renders the implicit equation for a torus.

Read snippet: Distance Render

Parametric UV Surface

var matrix:Matrix3D = new Matrix3D();
var verts:Vector.<Number> = new Vector.<Number>();
var pVerts:Vector.<Number> = new Vector.<Number>();
var uvts:Vector.<Number> = new Vector.<Number>();
var sqrt2:Number = Math.sqrt(2)
var pi:Number = Math.PI;
var pi23:Number= 2 * Math.PI / 3;
var step:Number= pi / 50;
for (var u:Number = -pi; u<pi; u+=step) {
	for (var v:Number = -pi; v<pi; v+=step) {
		// from here http://local.wasp.uwa.edu.au/~pbourke/geometry/hexatorus/
		var px = Math.sin(u) / Math.abs(sqrt2+ Math.cos(v))
        var py = Math.sin(u+pi23) / Math.abs(sqrt2 +Math.cos(v + pi23))
        var pz = Math.cos(u-pi23) / Math.abs(sqrt2 +Math.cos(v - pi23))
		verts.push(px * 50);
		verts.push(py * 50);
		verts.push(pz * 50);
	}
}
var brush:BitmapData=new BitmapData(3,2,true,0x41FFFFFF);
var canvas:BitmapData=new BitmapData(400,400,false,0x000000);
addChild(new Bitmap(canvas));
var dx:Number=0;
var dy:Number=0;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	dx += (mouseX - dx)/4;
	dy += (mouseY - dy)/4;
	matrix.identity();
	matrix.appendRotation(dy,Vector3D.X_AXIS);
	matrix.appendRotation(dx,Vector3D.Y_AXIS);
	matrix.appendTranslation(200, 200, 0);
	Utils3D.projectVectors(matrix, verts, pVerts, uvts);
	canvas.lock();
	canvas.fillRect(canvas.rect, 0x000000);
	var p = new Point();
	for (var i:int = 0; i<pVerts.length; i+=2) {
		p.x = pVerts[i];
		p.y = pVerts[i+1];
		canvas.copyPixels(brush, brush.rect, p, null, null, true);
	}
	canvas.unlock();
}

More 3D shapes inspired by (taken from) Paul Bourke’s website. I figured I should probably add a parametric 3D surface to this set of posts – so I chose to plot the Triaxial Hexatorus. It’s important to note that U and V go from -PI to PI.

I googled Triaxial Hexatorus and stumbled upon a great papervision demo that creates meshes using parametric equations – it also morphs between shapes.

I also noticed that I don’t need to populate the uvts or pVerts Vectors with zeros – seems to work fine without doing that.

Read snippet: Parametric UV Surface

Wormhole

var matrix:Matrix3D = new Matrix3D();
var verts:Vector.<Number> = new Vector.<Number>();
var pVerts:Vector.<Number> = new Vector.<Number>();
var uvts:Vector.<Number> = new Vector.<Number>();
for (var i:Number = -10; i<10; i+=.04) {
	for (var j:Number = -5; j<8; j+=.04) {
		for (var k:Number = -10; k<10; k+=.04) {
			var s:Number =  i * i * j + j * k * k;
			if (s <10 && s > 9.95) {
				verts.push(i * 20);
				verts.push(j * 20);
				verts.push(k * 20);
				pVerts.push(0),pVerts.push(0);
				uvts.push(0),uvts.push(0),uvts.push(0);
			}
		}
	}
}
var brush:BitmapData=new BitmapData(3,2,true,0x41FFFFFF);
var canvas:BitmapData=new BitmapData(400,400,false,0x000000);
addChild(new Bitmap(canvas));
var dx:Number=0;
var dy:Number=0;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	dx += (mouseX - dx)/4;
	dy += (mouseY - dy)/4;
	matrix.identity();
	matrix.appendRotation(dy,Vector3D.X_AXIS);
	matrix.appendRotation(dx,Vector3D.Y_AXIS);
	matrix.appendTranslation(200, 200, 0);
	Utils3D.projectVectors(matrix, verts, pVerts, uvts);
	canvas.lock();
	canvas.fillRect(canvas.rect, 0x000000);
	var p = new Point();
	for (var i:int = 0; i<pVerts.length; i+=2) {
		p.x = pVerts[i];
		p.y = pVerts[i+1];
		canvas.copyPixels(brush, brush.rect, p, null, null, true);
	}
	canvas.unlock();
}

Yet another variation on the post from the last two days. This one plots something resembling a wormhole – I was randomly tweaking the equation for a sphere and stumbled upon this…

Read snippet: Wormhole

Implicit 3D Plot

var matrix:Matrix3D = new Matrix3D();
var verts:Vector.<Number> = new Vector.<Number>();
var pVerts:Vector.<Number> = new Vector.<Number>();
var uvts:Vector.<Number> = new Vector.<Number>();
for (var i:Number = -2; i<2; i+=.04) {
	for (var j:Number = -2; j<2; j+=.04) {
		for (var k:Number = -2; k<2; k+=.04) {
			// blobby, from here www.iiit.net/techreports/ImplicitTR.pdf
var s:Number=i*i+j*j+k*k+Math.sin(4*i)-Math.cos(4*j)+Math.sin(4*k)-1;
			if (s<0&&s>-.2) {
				verts.push(i * 60);
				verts.push(j * 60);
				verts.push(k * 60);
				pVerts.push(0),pVerts.push(0);
				uvts.push(0),uvts.push(0),uvts.push(0);
			}
		}
	}
}
var brush:BitmapData=new BitmapData(3,2,true,0x41FFFFFF);
var canvas:BitmapData=new BitmapData(400,400,false,0x000000);
addChild(new Bitmap(canvas));
var dx:Number=0;
var dy:Number=0;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	dx += (mouseX - dx)/4;
	dy += (mouseY - dy)/4;
	matrix.identity();
	matrix.appendRotation(dy,Vector3D.X_AXIS);
	matrix.appendRotation(dx,Vector3D.Y_AXIS);
	matrix.appendTranslation(200, 200, 0);
	Utils3D.projectVectors(matrix, verts, pVerts, uvts);
	canvas.lock();
	canvas.fillRect(canvas.rect, 0x000000);
	var p = new Point();
	for (var i:int = 0; i<pVerts.length; i+=2) {
		p.x = pVerts[i];
		p.y = pVerts[i+1];
		canvas.copyPixels(brush, brush.rect, p, null, null, true);
	}
	canvas.unlock();
}

I was looking at some equations for implicit 3D surfaces in this pdf about raytracing… anyway, I realized I could just modify the Utils3D.projectVectors() code (that I wrote a little while ago) to easily render any of the implicit equations mentioned in the pdf. I also did some experimentation with fake lighting and distance rendering which I may post in the future.

(check out the swf on wonderfl.net)

Here are some stills of the above snippet:

Read snippet: Implicit 3D Plot

Random Equation Attractor

[SWF(width = 800, height = 800)]
var a:Number = 0.19;
var b:Number = .9;
var c:Number = 1.3
var xn1:Number = 5;
var yn1:Number = 0;
var xn:Number, yn:Number;

var scale:Number =40;
var iterations:Number = 20000;

function f(x:Number):Number{
	// too lazy to simplify this at the moment
	return((x + .1 + x * (a - c) * x) / (1.1 + a * (c*c + a*a)  * x * x )) * 1.3;
}
 
var canvas:BitmapData = Bitmap(addChild(new Bitmap(new BitmapData(800,800,false,0xEFEFEF)))).bitmapData;
																	   
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	
    canvas.fillRect(canvas.rect, 0xEFEFEF);
	 
	c +=  ((stage.stageWidth/2 - mouseX) / 8000 - c) / 2;
	
	xn1 = 0;
	yn1 = 0;
	for (var i:int = 0; i<iterations; i++){
		  xn = xn1;
		  yn = yn1;
		  
          xn1 = -xn - a + c +  f(yn);
          yn1 = -xn + c * f(xn * yn); 
		  canvas.setPixel( 380 + xn1 * scale, 450 + yn1 * scale, 0x000000);
	}
}

I was randomly messing around with strange attractors a few weeks back and this is one of the better results…. I arbitrarily altered equations until I got a nice result. You can move your mouse left and right to alter some of the params. Here is what it looks like when your mouse is in the middle of the screen:

Read snippet: Random Equation Attractor

Gradient Tooth

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

var a:Number=-1.21;
var r:Rectangle=new Rectangle(0,0,3,5);
var halfWidth:Number=canvas.width/2;
var halfHeight:Number=canvas.height/2;

render();

function render():void{
	for (var x:Number = -2; x<=2; x+=.01) {
		for (var y:Number = -2; y<=2; y+=.02) {
	
			// equation from : http://en.wikipedia.org/wiki/Bicuspid_curve
			//(x^2 - a^2) * (x - a)^2 + (y^2 - a^2) * (y^2 - a^2) = 0
	
			// unpoptimized:
			// var e:Number = (x*x - a*a) * (x-a)*(x-a) + (y*y-a*a) * (y*y-a*a);  
			// optimized:
			var x_a:Number=x-a;
			// factoring: x^2 - a^2 = (x + a) * (x - a)
			var y2_a2:Number =  (y + a) * (y - a);
			var e:Number = (x + a) * x_a * x_a *  x_a +  y2_a2 * y2_a2;
			 
				r.x=halfWidth+y*50;
				r.y=halfHeight-x*100;
				var col:Number = e * 50;
				if (col < 10){
					col = Math.abs(col) + 70;
				    canvas.fillRect(r, col << 16 | col << 8 | col );
				}
		}
	}
}

This is a variation on a post from a little while back…. it plots a modified Bicuspid that resembles a tooth:

Read snippet: Gradient Tooth

Swirl Gradient

var canvas:BitmapData=new BitmapData(200,200,false,0x000000);
addChild(new Bitmap(canvas));
scaleX=scaleY=2;
var pixNum:int=canvas.width*canvas.height;

var xp:Vector.<int> = new Vector.<int>();
var yp:Vector.<int> = new Vector.<int>();
var radius:Vector.<Number> = new Vector.<Number>();
var theta:Vector.<Number> = new Vector.<Number>();
for (var i:int = 0; i<pixNum; i++) {
	xp.push(i % 200);
	yp.push(int(i / 200));
	var dx:Number=100-xp[i];
	var dy:Number=100-yp[i];
	theta.push(Math.atan2(dy, dx));
	radius.push(Math.sqrt(dx * dx + dy * dy)/20);
}

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	canvas.lock();
	var n:Number = mouseX / 100;
	for (var i:int = 0; i<pixNum; i++) {
		var swirl:Number = 1+Math.sin(6*Math.cos(radius[i]) -n*theta[i]);
		canvas.setPixel(xp[i], yp[i],  Math.abs(255 - swirl * 255));
	}
	canvas.unlock();
}

This snippet creates a swirl gradient. While this snippet is not highly optimized, it does implement a basic optimization technique … I cache some repetitive calculations in Vectors and then use them on the main loop.

I got the function for a swirl gradient from mathworld…

Read snippet: Swirl Gradient

Slow Line Drawing

var canvas:BitmapData = Bitmap(addChild(new Bitmap(new BitmapData(400, 400, false, 0x000000)))).bitmapData;

function line(x1:Number, y1:Number, x2:Number, y2:Number, res:int=10):void{
	var dx:Number = x2 - x1;
	var dy:Number = y2 - y1;
	var dist:Number = Math.sqrt((dx * dx) + (dy * dy));
	var step:Number = 1 / (dist / res);
	for (var i:Number = 0; i<=1; i+= step){
		// lerp : a  + (b - a) * f
		canvas.setPixel(x1 + dx * i, y1 + dy * i, 0xFFFFFF);
	}
}

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
   canvas.fillRect(canvas.rect, 0x000000);
  line(100 , 100, mouseX, mouseY,1);
  line(100 + 50, 100, mouseX+ 50, mouseY,5);
}

Yesterday I posted an implementation of the Bresenham Line Algorithm. Today I’m posting a comparatively slow way to draw a line with setPixel(). This snippet uses lerp and the Pythagorean theorem. It works nicely for small numbers of lines, its easy to draw dotted lines with it and its easy to explain. In a real app where you needed to use setPixel() to draw a line you should use one of the fast algorithms like Wu or Bresenham.

I didn’t originally write this snippet to use set pixel… a few weeks ago I wrote something very similar to calculate a set of x y coords between two given points. In the program I used it in speed wasn’t an issue (as I only needed to run the function one time). I’ve needed this kind of function many times before in games and small apps…

This was the original:

function calculatePoints(x1:Number, y1:Number, x2:Number, y2:Number, res:int=10):Array{
	var points:Array = new Array();
	var dx:Number = x2 - x1;
	var dy:Number = y2 - y1;
	var dist:Number = Math.sqrt((dx * dx) + (dy * dy));
	var step:Number = 1 / (dist / res);
	for (var i:Number = 0; i<=1; i+= step){
		points.push(new Point(x1 + dx * i, y1 + dy * i));
	}
	return points;
}

trace(calculatePoints(0,0,100,0,10));
/* outputs:
(x=0, y=0),(x=10, y=0),(x=20, y=0),(x=30.000000000000004, y=0),(x=40, y=0),(x=50, y=0),(x=60, y=0),(x=70, y=0),(x=80, y=0),(x=89.99999999999999, y=0),(x=99.99999999999999, y=0)
*/

…and another version to allow you to specify the number of points to calculate rather than the pixel interval at which they should be calculated:

function calculatePoints(x1:Number, y1:Number, x2:Number, y2:Number, pointNum:int=10):Array{
	var points:Array = new Array();
	var step:Number = 1 / (pointNum + 1);
	for (var i:Number = 0; i<=1; i+= step){
		points.push(new Point(x1 + (x2 - x1) * i, y1 + (y2 - y1) * i));
	}
	return points;
}

trace(calculatePoints(0,30,30,0,1));
/* outputs:
(x=0, y=30),(x=15, y=15),(x=30, y=0)
*/

This last version isn’t perfect, sometimes the pointNum will be off by 1, I may fix that in a future post.

Read snippet: Slow Line Drawing