<?php
	

	$image_width = 600;
	$image_height = 500;
	$output_width = 100;
	$output_height = 100;
	$width = 30;
	$height = 13;
	$x_scale = 15;
	$y_scale =  20;
	$x_rot = 4;
	$y_rot = 3;
	$z_rot = -1;
	$fov = 45;
	$x_offset = 120;
	$y_offset = 30;
	$z_offset = -500;
	$randomlength = 3;
	$font_height = 18;
	$origin = Array($image_width/2, $image_height/3, 0);
	
	define('X', 0);
	define('Y', 1);
	define('Z', 2);
	define('R', 5);
	define('G', 1);
	define('B', 2);
	define('COLOUR', 3);
	
	function proj_matrix($matrix, $fov)
	{
		global $image_width;
		global $image_height;
		
		// find distance to project plane
		$d = cos($fov/2)/sin($fov/2);
		$dX = $d * ($image_width/2);
		$dY = $d * ($image_height/2);
		$width = count($matrix);
		$newmatrix = Array();
		for($i = 0; $i < $width; $i++)
		{
			$height = count($matrix[$i]);
			for($ii = 0; $ii < $height; $ii++)
			{
				if($matrix[$i][$ii][2] == 0)
					continue;
					
				// find reciprocal to multiple
				$zinv = 1.0/$matrix[$i][$ii][2];
				$newmatrix[$i][$ii][X] = $matrix[$i][$ii][X] * $dX * $zinv;
				$newmatrix[$i][$ii][Y] = $matrix[$i][$ii][Y] * $dY * $zinv;
				$newmatrix[$i][$ii][Z] = $matrix[$i][$ii][Z];
				$newmatrix[$i][$ii][COLOUR] = $matrix[$i][$ii][COLOUR];
			}
		}
		return $newmatrix;
	}
	function scale($matrix, $x, $y, $z)
	{
		$width = count($matrix);
		for($i = 0; $i < $width; $i++)
		{
			$height = count($matrix[$i]);
			for($ii = 0; $ii < $height; $ii++)
			{
				$matrix[$i][$ii][X] *= $x;
				$matrix[$i][$ii][Y] *= $y;
				$matrix[$i][$ii][Z] *= $z;
			}
		}
		return $matrix;
	}
	function translate($matrix, $x, $y, $z)
	{
		$width = count($matrix);
		for($i = 0; $i < $width; $i++)
		{
			$height = count($matrix[$i]);
			for($ii = 0; $ii < $height; $ii++)
			{
				$matrix[$i][$ii][X] += $x;
				$matrix[$i][$ii][Y] += $y;
				$matrix[$i][$ii][Z] += $z;
			}
		}
		return $matrix;
	}
	function rotate_x($matrix, $a)
	{
		$width = count($matrix);
		$newmatrix = Array();
		for($i = 0; $i < $width; $i++)
		{
			$height = count($matrix[$i]);
			for($ii = 0; $ii < $height; $ii++)
			{
				$newmatrix[$i][$ii][X] = $matrix[$i][$ii][X];
				$newmatrix[$i][$ii][Y] = $matrix[$i][$ii][Y]*cos($a) - $matrix[$i][$ii][Z]*sin($a);
				$newmatrix[$i][$ii][Z] = $matrix[$i][$ii][Y]*sin($a) + $matrix[$i][$ii][Z]*cos($a);
				$newmatrix[$i][$ii][COLOUR] = $matrix[$i][$ii][COLOUR];
			}
		}
		return $newmatrix;
	}
	function rotate_y($matrix, $a)
	{
		$width = count($matrix);
		$newmatrix = Array();
		for($i = 0; $i < $width; $i++)
		{
			$height = count($matrix[$i]);
			for($ii = 0; $ii < $height; $ii++)
			{
				$newmatrix[$i][$ii][X] = $matrix[$i][$ii][X]*cos($a) - $matrix[$i][$ii][Z]*sin($a);
				$newmatrix[$i][$ii][Y] = $matrix[$i][$ii][Y];
				$newmatrix[$i][$ii][Z] = $matrix[$i][$ii][X]*sin($a) + $matrix[$i][$ii][Z]*cos($a);
				$newmatrix[$i][$ii][COLOUR] = $matrix[$i][$ii][COLOUR];
			}
		}
		return $newmatrix;
	}
	function rotate_z($matrix, $a)
	{
		$width = count($matrix);
		$newmatrix = Array();
		for($i = 0; $i < $width; $i++)
		{
			$height = count($matrix[$i]);
			for($ii = 0; $ii < $height; $ii++)
			{
				$newmatrix[$i][$ii][X] = $matrix[$i][$ii][X]*cos($a) - $matrix[$i][$ii][Y]*sin($a);
				$newmatrix[$i][$ii][Y] = $matrix[$i][$ii][X]*sin($a) + $matrix[$i][$ii][Y]*cos($a);
				$newmatrix[$i][$ii][Z] = $matrix[$i][$ii][Z];
				$newmatrix[$i][$ii][COLOUR] = $matrix[$i][$ii][COLOUR];
			}
		}
		return $newmatrix;
	}
	function readfont($file)
	{
		// read font
		if(($contents = file($file)) === FALSE)
			die("cannot read font file!");
		$length = count($contents);
		$font['width'] = intval($contents[0]);
		$font['height'] = intval($contents[1]);
		$num = 0;
		$heightcounter = 0;
		for($line = 2; $line < $length; $line++)
		{
			for($i = 0; $i < $font['width']; $i++)
			{
				if($contents[$line][$i] === "#")
					$font[$num][$heightcounter][$i] = 1;
				else
					$font[$num][$heightcounter][$i] = 0;	
			}
			$heightcounter++;
			if($heightcounter >= $font['height']) {
				$heightcounter = 0;
				$num++;
			}
		}
		return $font;
	}
	
	function drawstring($x, $y, $h, $matrix, $s, $font,$colour)
	{
		if(!is_numeric($s))
			return FALSE;
		$length = strlen($s);
		for($i = 0; $i < $length; $i++)
		{
			for($ii = 0; $ii < $font['height']; $ii++)
			{
				for($iii = 0; $iii < $font['width']; $iii++)
				{
					if($font[intval($s[$i])][$ii][$iii])
					{
						$matrix[$x+$iii][$y+$ii][Z] += $h;
						$matrix[$x+$iii][$y+$ii][COLOUR] = $colour;
					}
				}
			}
			$x += $font['width'] + 1;
		}
		return $matrix;
	}
	function register_colour(&$map, &$image, $r, $g, $b)
	{
		if(array_key_exists($r, $map) && array_key_exists($g, $map[$r]) && array_key_exists($b, $map[$r][$g]))
			return $map[$r][$g][$b];
		else
			return ($map[$r][$g][$b] = imagecolorallocate($image, $r, $g, $b));
	}
	
	srand((double)microtime()*1000000);
	
	// create image and color pallete
	$image = imagecreatetruecolor($image_width, $image_height);
	$white = imagecolorallocate($image, 0x36, 0x36, 0x36);
	imagefilledrectangle($image, 0,0, $image_width, $image_height, $white);
	$colourmap = Array();
	


	
	// fill in default array
	$matrix = Array();
	for($i = 0; $i < $width; $i++)
	{
		$matrix[$i] = Array();
		for($ii = 0; $ii < $height; $ii++)
		{
			$r = rand(0, 0);
			$g = rand(0, 0);
			$b = rand(0, 0);
			$matrix[$i][$ii] = Array($i*$x_scale, $ii*$y_scale, 0, Array($r, $g, $b));
		}
	}
		
	$rs = "";
	for ($i = 0; $i < $randomlength; $i++) {
	  $rs .= rand(0,9);
	}
	
	session_start();
	$_SESSION['captcha_string'] = $rs;
	
	// Read font
	$font = readfont("captcha.txt");
	if(($matrix = drawstring(2,1,$font_height,$matrix, $rs, $font, Array(0xff, 0xff, 0xff))) === FALSE)
		die("string is not numeric");
	
	// translate so we can rotate around centre
	$matrix = translate($matrix, -$origin[0], -$origin[1], -$origin[2]);
	if(($matrix = rotate_z($matrix, -1)) === FALSE)
		die("error rotating matrix on the z axis");
	if(($matrix = rotate_x($matrix, 4)) === FALSE)
		die("error rotating matrix on the x axis");
	if(($matrix = rotate_y($matrix, 3)) === FALSE)
		die("error rotating matrix on the x axis");

	// restore origin since we will be drawing only on the positive axis
	$matrix = translate($matrix, 0, 0, $origin[2]+$z_offset);
	$matrix = proj_matrix($matrix, $fov);
	$matrix = translate($matrix, $origin[0]+$x_offset, $origin[1]+$y_offset, 0);

	// draw first row
	for($i = 1; $i < $width; $i++)
	{
		$r = intval(($matrix[$i-1][0][COLOUR][R] + $matrix[$i][0][COLOUR][R])/2);
		$g = intval(($matrix[$i-1][0][COLOUR][G] + $matrix[$i][0][COLOUR][G])/2);
		$b = intval(($matrix[$i-1][0][COLOUR][B] + $matrix[$i][0][COLOUR][B])/2);
		$c = register_colour($colourmap, $image, $r, $g, $b);
		imageline($image, $matrix[$i-1][0][X], $matrix[$i-1][0][Y], $matrix[$i][0][X], $matrix[$i][0][Y], $c);  
	}
	// draw first column
	for($ii = 1; $ii < $height; $ii++)
	{
		$r = intval(($matrix[0][$ii-1][COLOUR][R] + $matrix[0][$ii][COLOUR][R])/2);
		$g = intval(($matrix[0][$ii-1][COLOUR][G] + $matrix[0][$ii][COLOUR][G])/2);
		$b = intval(($matrix[0][$ii-1][COLOUR][B] + $matrix[0][$ii][COLOUR][B])/2);
		$c = register_colour($colourmap, $image, $r, $g, $b);
		imageline($image, $matrix[0][$ii-1][X], $matrix[0][$ii-1][Y], $matrix[0][$ii][X], $matrix[0][$ii][Y], $c);  
	}
	// draw rest

	for($i = 1; $i < $width; $i++)
	{
		for($ii = 1; $ii < $height; $ii++)
		{
			$r = intval(($matrix[$i-1][$ii][COLOUR][R] + $matrix[$i][$ii][COLOUR][R])/2);
			$g = intval(($matrix[$i-1][$ii][COLOUR][G] + $matrix[$i][$ii][COLOUR][G])/2);
			$b = intval(($matrix[$i-1][$ii][COLOUR][B] + $matrix[$i][$ii][COLOUR][B])/2);
			$c = register_colour($colourmap, $image, $r, $g, $b);
			imageline($image, $matrix[$i-1][$ii][X], $matrix[$i-1][$ii][Y], $matrix[$i][$ii][X], $matrix[$i][$ii][Y], $c);  
			$r = intval(($matrix[$i][$ii-1][COLOUR][R] + $matrix[$i][$ii][COLOUR][R])/2);
			$g = intval(($matrix[$i][$ii-1][COLOUR][G] + $matrix[$i][$ii][COLOUR][G])/2);
			$b = intval(($matrix[$i][$ii-1][COLOUR][B] + $matrix[$i][$ii][COLOUR][B])/2);
			$c = register_colour($colourmap, $image, $r, $g, $b);
			imageline($image, $matrix[$i][$ii-1][X], $matrix[$i][$ii-1][Y], $matrix[$i][$ii][X], $matrix[$i][$ii][Y], $c); 
		}
	}
	  
	
	header('Expires: Mon, 01 Jan 2000 00:00:00 GMT');
	header('Last-Modified: ' . gmdate("D, d M Y H:i:s") . ' GMT');
	header('Cache-Control: no-store, no-cache, must-revalidate');
	header('Cache-Control: post-check=0, pre-check=0', false);
	header('Pragma: no-cache');
	header('Content-type: image/png');
		
	if($output_width != $image_width || $output_height != $image_height)
	{
		$small = imagecreatetruecolor($output_width, $output_height);
		imagecopyresampled($small, $image, 0, 0, 0, 0, $output_width, $output_height, $image_width, $image_height);
		imagepng($small);
		imagedestroy($small);
	}
	else
	{
		imagepng($image);
	}
	imagedestroy($image);
?>