Blame Identity/Webenv/phpBB/3.0.4/includes/captcha/captcha_gd.php

ef5584
ef5584
/**
ef5584
*
ef5584
* @package VC
ef5584
* @version $Id: captcha_gd.php 8479 2008-03-29 00:22:48Z naderman $
ef5584
* @copyright (c) 2006 phpBB Group
ef5584
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
ef5584
*
ef5584
*/
ef5584
ef5584
/**
ef5584
* @ignore
ef5584
*/
ef5584
if (!defined('IN_PHPBB'))
ef5584
{
ef5584
	exit;
ef5584
}
ef5584
ef5584
/**
ef5584
* Original Author - Xore (Robert Hetzler)
ef5584
* With contributions from Neothermic
ef5584
*
ef5584
* @package VC
ef5584
*/
ef5584
class captcha
ef5584
{
ef5584
	var $width = 360;
ef5584
	var $height = 96;
ef5584
ef5584
	/**
ef5584
	* Create the image containing $code with a seed of $seed
ef5584
	*/
ef5584
	function execute($code, $seed)
ef5584
	{
ef5584
		global $config;
ef5584
		srand($seed);
ef5584
		mt_srand($seed);
ef5584
ef5584
		// Create image
ef5584
		$img = imagecreatetruecolor($this->width, $this->height);
ef5584
ef5584
		// Generate colours
ef5584
		$colour = new colour_manager($img, array(
ef5584
			'random'	=> true,
ef5584
			'min_value'	=> 60,
ef5584
		), 'hsv');
ef5584
ef5584
		$scheme = $colour->colour_scheme('background', false);
ef5584
		$scheme = $colour->mono_range($scheme, 10, false);
ef5584
		shuffle($scheme);
ef5584
ef5584
		$bg_colours = array_splice($scheme, mt_rand(6, 12));
ef5584
ef5584
		// Generate code characters
ef5584
		$characters = $sizes = $bounding_boxes = array();
ef5584
		$width_avail = $this->width - 15;
ef5584
		$code_len = strlen($code);
ef5584
ef5584
		$captcha_bitmaps = $this->captcha_bitmaps();
ef5584
		for ($i = 0; $i < $code_len; ++$i)
ef5584
		{
ef5584
			$characters[$i] = new char_cube3d($captcha_bitmaps, $code[$i]);
ef5584
ef5584
			list($min, $max) = $characters[$i]->range();
ef5584
			$sizes[$i] = mt_rand($min, $max);
ef5584
ef5584
			$box = $characters[$i]->dimensions($sizes[$i]);
ef5584
			$width_avail -= ($box[2] - $box[0]);
ef5584
			$bounding_boxes[$i] = $box;
ef5584
		}
ef5584
ef5584
		// Redistribute leftover x-space
ef5584
		$offset = array();
ef5584
		for ($i = 0; $i < $code_len; ++$i)
ef5584
		{
ef5584
			$denom = ($code_len - $i);
ef5584
			$denom = max(1.3, $denom);
ef5584
			$offset[$i] = mt_rand(0, (1.5 * $width_avail) / $denom);
ef5584
			$width_avail -= $offset[$i];
ef5584
		}
ef5584
ef5584
		if ($config['captcha_gd_x_grid'])
ef5584
		{
ef5584
			$grid = (int) $config['captcha_gd_x_grid'];
ef5584
			for ($y = 0; $y < $this->height; $y += mt_rand($grid - 2, $grid + 2))
ef5584
			{
ef5584
				$current_colour = $scheme[array_rand($scheme)];
ef5584
				imageline($img, mt_rand(0,4), mt_rand($y - 3, $y), mt_rand($this->width - 5, $this->width), mt_rand($y - 3, $y), $current_colour);
ef5584
			}
ef5584
		}
ef5584
ef5584
		if ($config['captcha_gd_y_grid'])
ef5584
		{
ef5584
			$grid = (int) $config['captcha_gd_y_grid'];
ef5584
			for ($x = 0; $x < $this->width; $x += mt_rand($grid - 2, $grid + 2))
ef5584
			{
ef5584
				$current_colour = $scheme[array_rand($scheme)];
ef5584
				imagedashedline($img, mt_rand($x -3, $x + 3), mt_rand(0, 4), mt_rand($x -3, $x + 3), mt_rand($this->height - 5, $this->height), $current_colour);
ef5584
			}
ef5584
		}
ef5584
ef5584
		$xoffset = 5;
ef5584
		for ($i = 0; $i < $code_len; ++$i)
ef5584
		{
ef5584
			$dimm = $bounding_boxes[$i];
ef5584
			$xoffset += ($offset[$i] - $dimm[0]);
ef5584
			$yoffset = mt_rand(-$dimm[1], $this->height - $dimm[3]);
ef5584
ef5584
			$characters[$i]->drawchar($sizes[$i], $xoffset, $yoffset, $img, $colour->get_resource('background'), $scheme);
ef5584
			$xoffset += $dimm[2];
ef5584
		}
ef5584
		
ef5584
		if ($config['captcha_gd_foreground_noise'])
ef5584
		{
ef5584
			$this->noise_line($img, 0, 0, $this->width, $this->height, $colour->get_resource('background'), $scheme, $bg_colours);
ef5584
		}
ef5584
ef5584
		// Send image
ef5584
		header('Content-Type: image/png');
ef5584
		header('Cache-control: no-cache, no-store');
ef5584
		imagepng($img);
ef5584
		imagedestroy($img);
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* Noise line
ef5584
	*/
ef5584
	function noise_line($img, $min_x, $min_y, $max_x, $max_y, $bg, $font, $non_font)
ef5584
	{
ef5584
		imagesetthickness($img, 2);
ef5584
ef5584
		$x1 = $min_x;
ef5584
		$x2 = $max_x;
ef5584
		$y1 = $min_y;
ef5584
		$y2 = $min_y;
ef5584
ef5584
		do
ef5584
		{
ef5584
			$line = array_merge(
ef5584
				array_fill(0, mt_rand(30, 60), $non_font[array_rand($non_font)]),
ef5584
				array_fill(0, mt_rand(30, 60), $bg)
ef5584
			);
ef5584
ef5584
			imagesetstyle($img, $line);
ef5584
			imageline($img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED);
ef5584
ef5584
			$y1 += mt_rand(12, 35);
ef5584
			$y2 += mt_rand(12, 35);
ef5584
		}
ef5584
		while ($y1 < $max_y && $y2 < $max_y);
ef5584
ef5584
		$x1 = $min_x;
ef5584
		$x2 = $min_x;
ef5584
		$y1 = $min_y;
ef5584
		$y2 = $max_y;
ef5584
ef5584
		do
ef5584
		{
ef5584
			$line = array_merge(
ef5584
				array_fill(0, mt_rand(30, 60), $non_font[array_rand($non_font)]),
ef5584
				array_fill(0, mt_rand(30, 60), $bg)
ef5584
			);
ef5584
ef5584
			imagesetstyle($img, $line);
ef5584
			imageline($img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED);
ef5584
ef5584
			$x1 += mt_rand(20, 35);
ef5584
			$x2 += mt_rand(20, 35);
ef5584
		}
ef5584
		while ($x1 < $max_x && $x2 < $max_x);
ef5584
		imagesetthickness($img, 1);
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* Return bitmaps
ef5584
	*/
ef5584
	function captcha_bitmaps()
ef5584
	{
ef5584
		return array(
ef5584
			'width'		=> 9,
ef5584
			'height'	=> 15,
ef5584
			'data'		=> array(
ef5584
ef5584
			'A' => array(
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,1,0,1,0,0,0),
ef5584
				array(0,0,0,1,0,1,0,0,0),
ef5584
				array(0,0,0,1,0,1,0,0,0),
ef5584
				array(0,0,1,0,0,0,1,0,0),
ef5584
				array(0,0,1,0,0,0,1,0,0),
ef5584
				array(0,0,1,0,0,0,1,0,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,1,1,1,1,1,1,1,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
			),
ef5584
			'B' => array(
ef5584
				array(1,1,1,1,1,1,1,0,0),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,1,1,1,1,1,1,0,0),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,1,1,1,1,1,1,0,0),
ef5584
			),
ef5584
			'C' => array(
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
			),
ef5584
			'D' => array(
ef5584
				array(1,1,1,1,1,1,1,0,0),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,1,1,1,1,1,1,0,0),
ef5584
			),
ef5584
			'E' => array(
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,1,1,1,1,1,1,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
			),
ef5584
			'F' => array(
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,1,1,1,1,1,1,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
			),
ef5584
			'G' => array(
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,1,1,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
			),
ef5584
			'H' => array(
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
			),
ef5584
			'I' => array(
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
			),
ef5584
			'J' => array(
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(1,0,0,0,0,1,0,0,0),
ef5584
				array(1,0,0,0,0,1,0,0,0),
ef5584
				array(0,1,0,0,1,0,0,0,0),
ef5584
				array(0,0,1,1,0,0,0,0,0),
ef5584
			),
ef5584
			'K' => array(    // New 'K', supplied by NeoThermic
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,1,0,0),
ef5584
				array(1,0,0,0,0,1,0,0,0),
ef5584
				array(1,0,0,0,1,0,0,0,0),
ef5584
				array(1,0,0,1,0,0,0,0,0),
ef5584
				array(1,0,1,0,0,0,0,0,0),
ef5584
				array(1,1,0,0,0,0,0,0,0),
ef5584
				array(1,0,1,0,0,0,0,0,0),
ef5584
				array(1,0,0,1,0,0,0,0,0),
ef5584
				array(1,0,0,0,1,0,0,0,0),
ef5584
				array(1,0,0,0,0,1,0,0,0),
ef5584
				array(1,0,0,0,0,0,1,0,0),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
			),
ef5584
			'L' => array(
ef5584
				array(0,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
			),
ef5584
			'M' => array(
ef5584
				array(1,1,0,0,0,0,0,1,1),
ef5584
				array(1,1,0,0,0,0,0,1,1),
ef5584
				array(1,0,1,0,0,0,1,0,1),
ef5584
				array(1,0,1,0,0,0,1,0,1),
ef5584
				array(1,0,1,0,0,0,1,0,1),
ef5584
				array(1,0,0,1,0,1,0,0,1),
ef5584
				array(1,0,0,1,0,1,0,0,1),
ef5584
				array(1,0,0,1,0,1,0,0,1),
ef5584
				array(1,0,0,0,1,0,0,0,1),
ef5584
				array(1,0,0,0,1,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
			),
ef5584
			'N' => array(
ef5584
				array(1,1,0,0,0,0,0,0,1),
ef5584
				array(1,1,0,0,0,0,0,0,1),
ef5584
				array(1,0,1,0,0,0,0,0,1),
ef5584
				array(1,0,1,0,0,0,0,0,1),
ef5584
				array(1,0,0,1,0,0,0,0,1),
ef5584
				array(1,0,0,1,0,0,0,0,1),
ef5584
				array(1,0,0,0,1,0,0,0,1),
ef5584
				array(1,0,0,0,1,0,0,0,1),
ef5584
				array(1,0,0,0,1,0,0,0,1),
ef5584
				array(1,0,0,0,0,1,0,0,1),
ef5584
				array(1,0,0,0,0,1,0,0,1),
ef5584
				array(1,0,0,0,0,0,1,0,1),
ef5584
				array(1,0,0,0,0,0,1,0,1),
ef5584
				array(1,0,0,0,0,0,0,1,1),
ef5584
				array(1,0,0,0,0,0,0,1,1),
ef5584
			),
ef5584
			'O' => array(
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
			),
ef5584
			'P' => array(
ef5584
				array(1,1,1,1,1,1,1,0,0),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,1,1,1,1,1,1,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
			),
ef5584
			'Q' => array(
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,1,0,0,1),
ef5584
				array(1,0,0,0,0,0,1,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,1,1,1,1,0,1),
ef5584
			),
ef5584
			'R' => array(
ef5584
				array(1,1,1,1,1,1,1,0,0),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,1,1,1,1,1,1,0,0),
ef5584
				array(1,1,1,0,0,0,0,0,0),
ef5584
				array(1,0,0,1,0,0,0,0,0),
ef5584
				array(1,0,0,0,1,0,0,0,0),
ef5584
				array(1,0,0,0,0,1,0,0,0),
ef5584
				array(1,0,0,0,0,0,1,0,0),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
			),
ef5584
			'S' => array(
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(0,1,0,0,0,0,0,0,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
			),
ef5584
			'T' => array(
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
			),
ef5584
			'U' => array(
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
			),
ef5584
			'V' => array(
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,0,0,0,1,0,0),
ef5584
				array(0,0,1,0,0,0,1,0,0),
ef5584
				array(0,0,1,0,0,0,1,0,0),
ef5584
				array(0,0,1,0,0,0,1,0,0),
ef5584
				array(0,0,0,1,0,1,0,0,0),
ef5584
				array(0,0,0,1,0,1,0,0,0),
ef5584
				array(0,0,0,1,0,1,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
			),
ef5584
			'W' => array(    // New 'W', supplied by MHobbit
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,1,0,0,0,1),
ef5584
				array(1,0,0,0,1,0,0,0,1),
ef5584
				array(1,0,0,1,0,1,0,0,1),
ef5584
				array(1,0,0,1,0,1,0,0,1),
ef5584
				array(1,0,0,1,0,1,0,0,1),
ef5584
				array(1,0,1,0,0,0,1,0,1),
ef5584
				array(1,0,1,0,0,0,1,0,1),
ef5584
				array(1,0,1,0,0,0,1,0,1),
ef5584
				array(1,1,0,0,0,0,0,1,1),
ef5584
				array(1,1,0,0,0,0,0,1,1),
ef5584
			),
ef5584
			'X' => array(
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,0,0,0,1,0,0),
ef5584
				array(0,0,0,1,0,1,0,0,0),
ef5584
				array(0,0,0,1,0,1,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,1,0,1,0,0,0),
ef5584
				array(0,0,0,1,0,1,0,0,0),
ef5584
				array(0,0,1,0,0,0,1,0,0),
ef5584
				array(0,1,0,0,0,0,1,0,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
			),
ef5584
			'Y' => array(
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,0,0,0,1,0,0),
ef5584
				array(0,0,1,0,0,0,1,0,0),
ef5584
				array(0,0,0,1,0,1,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
			),
ef5584
			'Z' => array(    // New 'Z' supplied by Anon
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,0,1,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,1,0,0,0,0,0),
ef5584
				array(0,0,0,1,0,0,0,0,0),
ef5584
				array(0,0,1,0,0,0,0,0,0),
ef5584
				array(0,1,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
			),
ef5584
			'1' => array(
ef5584
				array(0,0,0,1,1,0,0,0,0),
ef5584
				array(0,0,1,0,1,0,0,0,0),
ef5584
				array(0,1,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,1,1,1,1,1,1,1,0),
ef5584
			),
ef5584
			'2' => array(    // New '2' supplied by Anon
ef5584
				array(0,0,0,1,1,1,0,0,0),
ef5584
				array(0,0,1,0,0,0,1,0,0),
ef5584
				array(0,1,0,0,0,0,1,1,0),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,1,1),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,0,1,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,1,0,0,0,0,0),
ef5584
				array(0,0,1,0,0,0,0,0,0),
ef5584
				array(0,1,0,0,0,0,0,0,0),
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
				array(0,0,0,0,0,0,0,0,0),
ef5584
			),
ef5584
			'3' => array(
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,1,1,0,0),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
			),
ef5584
			'4' => array(
ef5584
				array(0,0,0,0,0,0,1,1,0),
ef5584
				array(0,0,0,0,0,1,0,1,0),
ef5584
				array(0,0,0,0,1,0,0,1,0),
ef5584
				array(0,0,0,1,0,0,0,1,0),
ef5584
				array(0,0,1,0,0,0,0,1,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,1,0),
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
			),
ef5584
			'5' => array(
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(0,1,0,0,0,0,0,0,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
			),
ef5584
			'6' => array(
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,1,1,1,1,0,0),
ef5584
				array(1,0,1,0,0,0,0,1,0),
ef5584
				array(1,1,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
			),
ef5584
			'7' => array(
ef5584
				array(1,1,1,1,1,1,1,1,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,0,0,1,0),
ef5584
				array(0,0,0,0,0,0,1,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,0,1,0,0,0),
ef5584
				array(0,0,0,0,1,0,0,0,0),
ef5584
				array(0,0,0,1,0,0,0,0,0),
ef5584
				array(0,0,0,1,0,0,0,0,0),
ef5584
				array(0,0,1,0,0,0,0,0,0),
ef5584
				array(0,1,0,0,0,0,0,0,0),
ef5584
				array(0,1,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
				array(1,0,0,0,0,0,0,0,0),
ef5584
			),
ef5584
			'8' => array(
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
			),
ef5584
			'9' => array(
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,1,1),
ef5584
				array(0,1,0,0,0,0,1,0,1),
ef5584
				array(0,0,1,1,1,1,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(0,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(1,0,0,0,0,0,0,0,1),
ef5584
				array(0,1,0,0,0,0,0,1,0),
ef5584
				array(0,0,1,1,1,1,1,0,0),
ef5584
			),
ef5584
			)
ef5584
		);
ef5584
	}
ef5584
}
ef5584
ef5584
/**
ef5584
* @package VC
ef5584
*/
ef5584
class char_cube3d
ef5584
{
ef5584
	var $bitmap;
ef5584
	var $bitmap_width;
ef5584
	var $bitmap_height;
ef5584
ef5584
	var $basis_matrix = array(array(1, 0, 0), array(0, 1, 0), array(0, 0, 1));
ef5584
	var $abs_x = array(1, 0);
ef5584
	var $abs_y = array(0, 1);
ef5584
	var $x = 0;
ef5584
	var $y = 1;
ef5584
	var $z = 2;
ef5584
	var $letter = '';
ef5584
ef5584
	/**
ef5584
	*/
ef5584
	function char_cube3d(&$bitmaps, $letter)
ef5584
	{
ef5584
		$this->bitmap			= $bitmaps['data'][$letter];
ef5584
		$this->bitmap_width		= $bitmaps['width'];
ef5584
		$this->bitmap_height	= $bitmaps['height'];
ef5584
ef5584
		$this->basis_matrix[0][0] = mt_rand(-600, 600);
ef5584
		$this->basis_matrix[0][1] = mt_rand(-600, 600);
ef5584
		$this->basis_matrix[0][2] = (mt_rand(0, 1) * 2000) - 1000;
ef5584
		$this->basis_matrix[1][0] = mt_rand(-1000, 1000);
ef5584
		$this->basis_matrix[1][1] = mt_rand(-1000, 1000);
ef5584
		$this->basis_matrix[1][2] = mt_rand(-1000, 1000);
ef5584
ef5584
		$this->normalize($this->basis_matrix[0]);
ef5584
		$this->normalize($this->basis_matrix[1]);
ef5584
		$this->basis_matrix[2] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[1]);
ef5584
		$this->normalize($this->basis_matrix[2]);
ef5584
ef5584
		// $this->basis_matrix[1] might not be (probably isn't) orthogonal to $basis_matrix[0]
ef5584
		$this->basis_matrix[1] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[2]);
ef5584
		$this->normalize($this->basis_matrix[1]);
ef5584
ef5584
		// Make sure our cube is facing into the canvas (assuming +z == in)
ef5584
		for ($i = 0; $i < 3; ++$i)
ef5584
		{
ef5584
			if ($this->basis_matrix[$i][2] < 0)
ef5584
			{
ef5584
				$this->basis_matrix[$i][0] *= -1;
ef5584
				$this->basis_matrix[$i][1] *= -1;
ef5584
				$this->basis_matrix[$i][2] *= -1;
ef5584
			}
ef5584
		}
ef5584
ef5584
		// Force our "z" basis vector to be the one with greatest absolute z value
ef5584
		$this->x = 0;
ef5584
		$this->y = 1;
ef5584
		$this->z = 2;
ef5584
ef5584
		// Swap "y" with "z"
ef5584
		if ($this->basis_matrix[1][2] > $this->basis_matrix[2][2])
ef5584
		{
ef5584
			$this->z = 1;
ef5584
			$this->y = 2;
ef5584
		}
ef5584
ef5584
		// Swap "x" with "z"
ef5584
		if ($this->basis_matrix[0][2] > $this->basis_matrix[$this->z][2])
ef5584
		{
ef5584
			$this->x = $this->z;
ef5584
			$this->z = 0;
ef5584
		}
ef5584
ef5584
		// Still need to determine which of $x,$y are which.
ef5584
		// wrong orientation if y's y-component is less than it's x-component
ef5584
		// likewise if x's x-component is less than it's y-component
ef5584
		// if they disagree, go with the one with the greater weight difference.
ef5584
		// rotate if positive
ef5584
		$weight = (abs($this->basis_matrix[$this->x][1]) - abs($this->basis_matrix[$this->x][0])) + (abs($this->basis_matrix[$this->y][0]) - abs($this->basis_matrix[$this->y][1]));
ef5584
ef5584
		// Swap "x" with "y"
ef5584
		if ($weight > 0)
ef5584
		{
ef5584
			list($this->x, $this->y) = array($this->y, $this->x);
ef5584
		}
ef5584
ef5584
		$this->abs_x = array($this->basis_matrix[$this->x][0], $this->basis_matrix[$this->x][1]);
ef5584
		$this->abs_y = array($this->basis_matrix[$this->y][0], $this->basis_matrix[$this->y][1]);
ef5584
ef5584
		if ($this->abs_x[0] < 0)
ef5584
		{
ef5584
			$this->abs_x[0] *= -1;
ef5584
			$this->abs_x[1] *= -1;
ef5584
		}
ef5584
ef5584
		if ($this->abs_y[1] > 0)
ef5584
		{
ef5584
			$this->abs_y[0] *= -1;
ef5584
			$this->abs_y[1] *= -1;
ef5584
		}
ef5584
ef5584
		$this->letter = $letter;
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* Draw a character
ef5584
	*/
ef5584
	function drawchar($scale, $xoff, $yoff, $img, $background, $colours)
ef5584
	{
ef5584
		$width	= $this->bitmap_width;
ef5584
		$height	= $this->bitmap_height;
ef5584
		$bitmap	= $this->bitmap;
ef5584
ef5584
		$colour1 = $colours[array_rand($colours)];
ef5584
		$colour2 = $colours[array_rand($colours)];
ef5584
ef5584
		$swapx = ($this->basis_matrix[$this->x][0] > 0);
ef5584
		$swapy = ($this->basis_matrix[$this->y][1] < 0);
ef5584
ef5584
		for ($y = 0; $y < $height; ++$y)
ef5584
		{
ef5584
			for ($x = 0; $x < $width; ++$x)
ef5584
			{
ef5584
				$xp = ($swapx) ? ($width - $x - 1) : $x;
ef5584
				$yp = ($swapy) ? ($height - $y - 1) : $y;
ef5584
ef5584
				if ($bitmap[$height - $yp - 1][$xp])
ef5584
				{
ef5584
					$dx = $this->scale($this->abs_x, ($xp - ($swapx ? ($width / 2) : ($width / 2) - 1)) * $scale);
ef5584
					$dy = $this->scale($this->abs_y, ($yp - ($swapy ? ($height / 2) : ($height / 2) - 1)) * $scale);
ef5584
					$xo = $xoff + $dx[0] + $dy[0];
ef5584
					$yo = $yoff + $dx[1] + $dy[1];
ef5584
ef5584
					$origin = array(0, 0, 0);
ef5584
					$xvec = $this->scale($this->basis_matrix[$this->x], $scale);
ef5584
					$yvec = $this->scale($this->basis_matrix[$this->y], $scale);
ef5584
					$face_corner = $this->sum2($xvec, $yvec);
ef5584
ef5584
					$zvec = $this->scale($this->basis_matrix[$this->z], $scale);
ef5584
					$x_corner = $this->sum2($xvec, $zvec);
ef5584
					$y_corner = $this->sum2($yvec, $zvec);
ef5584
ef5584
					imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $xvec, $x_corner,$zvec), 4, $colour1);
ef5584
					imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $yvec, $y_corner,$zvec), 4, $colour2);
ef5584
ef5584
					$face = $this->gen_poly($xo, $yo, $origin, $xvec, $face_corner, $yvec);
ef5584
ef5584
					imagefilledpolygon($img, $face, 4, $background);
ef5584
					imagepolygon($img, $face, 4, $colour1);
ef5584
				}
ef5584
			}
ef5584
		}
ef5584
	}
ef5584
ef5584
	/*
ef5584
	* return a roughly acceptable range of sizes for rendering with this texttype
ef5584
	*/
ef5584
	function range()
ef5584
	{
ef5584
		return array(3, 4);
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* Vector length
ef5584
	*/
ef5584
	function vectorlen($vector)
ef5584
	{
ef5584
		return sqrt(pow($vector[0], 2) + pow($vector[1], 2) + pow($vector[2], 2));
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* Normalize
ef5584
	*/
ef5584
	function normalize(&$vector, $length = 1)
ef5584
	{
ef5584
		$length = (( $length < 1) ? 1 : $length);
ef5584
		$length /= $this->vectorlen($vector);
ef5584
		$vector[0] *= $length;
ef5584
		$vector[1] *= $length;
ef5584
		$vector[2] *= $length;
ef5584
	}
ef5584
ef5584
	/**
ef5584
	*/
ef5584
	function cross_product($vector1, $vector2)
ef5584
	{
ef5584
		$retval = array(0, 0, 0);
ef5584
		$retval[0] =  (($vector1[1] * $vector2[2]) - ($vector1[2] * $vector2[1]));
ef5584
		$retval[1] = -(($vector1[0] * $vector2[2]) - ($vector1[2] * $vector2[0]));
ef5584
		$retval[2] =  (($vector1[0] * $vector2[1]) - ($vector1[1] * $vector2[0]));
ef5584
ef5584
		return $retval;
ef5584
	}
ef5584
ef5584
	/**
ef5584
	*/
ef5584
	function sum($vector1, $vector2)
ef5584
	{
ef5584
		return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1], $vector1[2] + $vector2[2]);
ef5584
	}
ef5584
ef5584
	/**
ef5584
	*/
ef5584
	function sum2($vector1, $vector2)
ef5584
	{
ef5584
		return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1]);
ef5584
	}
ef5584
ef5584
	/**
ef5584
	*/
ef5584
	function scale($vector, $length)
ef5584
	{
ef5584
		if (sizeof($vector) == 2)
ef5584
		{
ef5584
			return array($vector[0] * $length, $vector[1] * $length);
ef5584
		}
ef5584
ef5584
		return array($vector[0] * $length, $vector[1] * $length, $vector[2] * $length);
ef5584
	}
ef5584
ef5584
	/**
ef5584
	*/
ef5584
	function gen_poly($xoff, $yoff, &$vec1, &$vec2, &$vec3, &$vec4)
ef5584
	{
ef5584
		$poly = array();
ef5584
		$poly[0] = $xoff + $vec1[0];
ef5584
		$poly[1] = $yoff + $vec1[1];
ef5584
		$poly[2] = $xoff + $vec2[0];
ef5584
		$poly[3] = $yoff + $vec2[1];
ef5584
		$poly[4] = $xoff + $vec3[0];
ef5584
		$poly[5] = $yoff + $vec3[1];
ef5584
		$poly[6] = $xoff + $vec4[0];
ef5584
		$poly[7] = $yoff + $vec4[1];
ef5584
ef5584
		return $poly;
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* dimensions
ef5584
	*/
ef5584
	function dimensions($size)
ef5584
	{
ef5584
		$xn = $this->scale($this->basis_matrix[$this->x], -($this->bitmap_width / 2) * $size);
ef5584
		$xp = $this->scale($this->basis_matrix[$this->x], ($this->bitmap_width / 2) * $size);
ef5584
		$yn = $this->scale($this->basis_matrix[$this->y], -($this->bitmap_height / 2) * $size);
ef5584
		$yp = $this->scale($this->basis_matrix[$this->y], ($this->bitmap_height / 2) * $size);
ef5584
ef5584
		$p = array();
ef5584
		$p[0] = $this->sum2($xn, $yn);
ef5584
		$p[1] = $this->sum2($xp, $yn);
ef5584
		$p[2] = $this->sum2($xp, $yp);
ef5584
		$p[3] = $this->sum2($xn, $yp);
ef5584
ef5584
		$min_x = $max_x = $p[0][0];
ef5584
		$min_y = $max_y = $p[0][1];
ef5584
ef5584
		for ($i = 1; $i < 4; ++$i)
ef5584
		{
ef5584
			$min_x = ($min_x > $p[$i][0]) ? $p[$i][0] : $min_x;
ef5584
			$min_y = ($min_y > $p[$i][1]) ? $p[$i][1] : $min_y;
ef5584
			$max_x = ($max_x < $p[$i][0]) ? $p[$i][0] : $max_x;
ef5584
			$max_y = ($max_y < $p[$i][1]) ? $p[$i][1] : $max_y;
ef5584
		}
ef5584
ef5584
		return array($min_x, $min_y, $max_x, $max_y);
ef5584
	}
ef5584
}
ef5584
ef5584
/**
ef5584
* @package VC
ef5584
*/
ef5584
class colour_manager
ef5584
{
ef5584
	var $img;
ef5584
	var $mode;
ef5584
	var $colours;
ef5584
	var $named_colours;
ef5584
ef5584
	/**
ef5584
	* Create the colour manager, link it to the image resource
ef5584
	*/
ef5584
	function colour_manager($img, $background = false, $mode = 'ahsv')
ef5584
	{
ef5584
		$this->img = $img;
ef5584
		$this->mode = $mode;
ef5584
		$this->colours = array();
ef5584
		$this->named_colours = array();
ef5584
ef5584
		if ($background !== false)
ef5584
		{
ef5584
			$bg = $this->allocate_named('background', $background);
ef5584
			imagefill($this->img, 0, 0, $bg);
ef5584
		}
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* Lookup a named colour resource
ef5584
	*/
ef5584
	function get_resource($named_colour)
ef5584
	{
ef5584
		if (isset($this->named_colours[$named_colour]))
ef5584
		{
ef5584
			return $this->named_colours[$named_colour];
ef5584
		}
ef5584
ef5584
		if (isset($this->named_rgb[$named_colour]))
ef5584
		{
ef5584
			return $this->allocate_named($named_colour, $this->named_rgb[$named_colour], 'rgb');
ef5584
		}
ef5584
ef5584
		return false;
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* Assign a name to a colour resource
ef5584
	*/
ef5584
	function name_colour($name, $resource)
ef5584
	{
ef5584
		$this->named_colours[$name] = $resource;
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* names and allocates a colour resource
ef5584
	*/
ef5584
	function allocate_named($name, $colour, $mode = false)
ef5584
	{
ef5584
		$resource = $this->allocate($colour, $mode);
ef5584
ef5584
		if ($resource !== false)
ef5584
		{
ef5584
			$this->name_colour($name, $resource);
ef5584
		}
ef5584
		return $resource;
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* allocates a specified colour into the image
ef5584
	*/
ef5584
	function allocate($colour, $mode = false)
ef5584
	{
ef5584
		if ($mode === false)
ef5584
		{
ef5584
			$mode = $this->mode;
ef5584
		}
ef5584
		
ef5584
		if (!is_array($colour))
ef5584
		{
ef5584
			if (isset($this->named_rgb[$colour]))
ef5584
			{
ef5584
				return $this->allocate_named($colour, $this->named_rgb[$colour], 'rgb');
ef5584
			}
ef5584
ef5584
			if (!is_int($colour))
ef5584
			{
ef5584
				return false;
ef5584
			}
ef5584
ef5584
			$mode = 'rgb';
ef5584
			$colour = array(255 & ($colour >> 16), 255 & ($colour >>  8), 255 & $colour);
ef5584
		}
ef5584
ef5584
		if (isset($colour['mode']))
ef5584
		{
ef5584
			$mode = $colour['mode'];
ef5584
			unset($colour['mode']);
ef5584
		}
ef5584
ef5584
		if (isset($colour['random']))
ef5584
		{
ef5584
			unset($colour['random']);
ef5584
			// everything else is params
ef5584
			return $this->random_colour($colour, $mode);
ef5584
		}
ef5584
ef5584
		$rgb		= colour_manager::model_convert($colour, $mode, 'rgb');
ef5584
		$store		= ($this->mode == 'rgb') ? $rgb : colour_manager::model_convert($colour, $mode, $this->mode);
ef5584
		$resource	= imagecolorallocate($this->img, $rgb[0], $rgb[1], $rgb[2]);
ef5584
		$this->colours[$resource] = $store;
ef5584
ef5584
		return $resource;
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* randomly generates a colour, with optional params
ef5584
	*/
ef5584
	function random_colour($params = array(), $mode = false)
ef5584
	{
ef5584
		if ($mode === false)
ef5584
		{
ef5584
			$mode = $this->mode;
ef5584
		}
ef5584
ef5584
		switch ($mode)
ef5584
		{
ef5584
			case 'rgb':
ef5584
				// @TODO random rgb generation. do we intend to do this, or is it just too tedious?
ef5584
			break;
ef5584
ef5584
			case 'ahsv':
ef5584
			case 'hsv':
ef5584
			default:
ef5584
ef5584
				$default_params = array(
ef5584
					'hue_bias'			=> false,	// degree / 'r'/'g'/'b'/'c'/'m'/'y'   /'o'
ef5584
					'hue_range'			=> false,	// if hue bias, then difference range +/- from bias
ef5584
					'min_saturation'	=> 30,		// 0 - 100
ef5584
					'max_saturation'	=> 80,		// 0 - 100
ef5584
					'min_value'			=> 30,		// 0 - 100
ef5584
					'max_value'			=> 80,		// 0 - 100
ef5584
				);
ef5584
ef5584
				$alt = ($mode == 'ahsv') ? true : false;
ef5584
				$params = array_merge($default_params, $params);
ef5584
ef5584
				$min_hue		= 0;
ef5584
				$max_hue		= 359;
ef5584
				$min_saturation	= max(0, $params['min_saturation']);
ef5584
				$max_saturation	= min(100, $params['max_saturation']);
ef5584
				$min_value		= max(0, $params['min_value']);
ef5584
				$max_value		= min(100, $params['max_value']);
ef5584
ef5584
				if ($params['hue_bias'] !== false)
ef5584
				{
ef5584
					if (is_numeric($params['hue_bias']))
ef5584
					{
ef5584
						$h = intval($params['hue_bias']) % 360;
ef5584
					}
ef5584
					else
ef5584
					{
ef5584
						switch ($params['hue_bias'])
ef5584
						{
ef5584
							case 'o':
ef5584
								$h = $alt ?  60 :  30;
ef5584
							break;
ef5584
ef5584
							case 'y':
ef5584
								$h = $alt ? 120 :  60;
ef5584
							break;
ef5584
ef5584
							case 'g':
ef5584
								$h = $alt ? 180 : 120;
ef5584
							break;
ef5584
ef5584
							case 'c':
ef5584
								$h = $alt ? 210 : 180;
ef5584
							break;
ef5584
ef5584
							case 'b':
ef5584
								$h = 240;
ef5584
							break;
ef5584
ef5584
							case 'm':
ef5584
								$h = 300;
ef5584
							break;
ef5584
ef5584
							case 'r':
ef5584
							default:
ef5584
								$h = 0;
ef5584
							break;
ef5584
						}
ef5584
					}
ef5584
ef5584
					$min_hue = $h + 360;
ef5584
					$max_hue = $h + 360;
ef5584
ef5584
					if ($params['hue_range'])
ef5584
					{
ef5584
						$min_hue -= min(180, $params['hue_range']);
ef5584
						$max_hue += min(180, $params['hue_range']);
ef5584
					}
ef5584
				}
ef5584
ef5584
				$h = mt_rand($min_hue, $max_hue);
ef5584
				$s = mt_rand($min_saturation, $max_saturation);
ef5584
				$v = mt_rand($min_value, $max_value);
ef5584
ef5584
				return $this->allocate(array($h, $s, $v), $mode);
ef5584
ef5584
			break;
ef5584
		}
ef5584
	}
ef5584
ef5584
	/**
ef5584
	*/
ef5584
	function colour_scheme($resource, $include_original = true)
ef5584
	{
ef5584
		$mode = 'hsv';
ef5584
ef5584
		if (($pre = $this->get_resource($resource)) !== false)
ef5584
		{
ef5584
			$resource = $pre;
ef5584
		}
ef5584
ef5584
		$colour = colour_manager::model_convert($this->colours[$resource], $this->mode, $mode);
ef5584
		$results = ($include_original) ? array($resource) : array();
ef5584
		$colour2 = $colour3 = $colour4 = $colour;
ef5584
		$colour2[0] += 150;
ef5584
		$colour3[0] += 180;
ef5584
		$colour4[0] += 210;
ef5584
ef5584
ef5584
		$results[] = $this->allocate($colour2, $mode);
ef5584
		$results[] = $this->allocate($colour3, $mode);
ef5584
		$results[] = $this->allocate($colour4, $mode);
ef5584
ef5584
		return $results;
ef5584
	}
ef5584
ef5584
	/**
ef5584
	*/
ef5584
	function mono_range($resource, $count = 5, $include_original = true)
ef5584
	{
ef5584
		if (is_array($resource))
ef5584
		{
ef5584
			$results = array();
ef5584
			for ($i = 0, $size = sizeof($resource); $i < $size; ++$i)
ef5584
			{
ef5584
				$results = array_merge($results, $this->mono_range($resource[$i], $count, $include_original));
ef5584
			}
ef5584
			return $results;
ef5584
		}
ef5584
ef5584
		$mode = (in_array($this->mode, array('hsv', 'ahsv'), true) ? $this->mode : 'ahsv');
ef5584
		if (($pre = $this->get_resource($resource)) !== false)
ef5584
		{
ef5584
			$resource = $pre;
ef5584
		}
ef5584
ef5584
		$colour = colour_manager::model_convert($this->colours[$resource], $this->mode, $mode);
ef5584
ef5584
		$results = array();
ef5584
		if ($include_original)
ef5584
		{
ef5584
			$results[] = $resource;
ef5584
			$count--;
ef5584
		}
ef5584
ef5584
		// This is a hard problem. I chicken out and try to maintain readability at the cost of less randomness.
ef5584
		
ef5584
		while ($count > 0)
ef5584
		{
ef5584
			$colour[1] = ($colour[1] + mt_rand(40,60)) % 99;
ef5584
			$colour[2] = ($colour[2] + mt_rand(40,60));
ef5584
			$results[] = $this->allocate($colour, $mode);
ef5584
			$count--;
ef5584
		}
ef5584
		return $results;
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* Convert from one colour model to another
ef5584
	*/
ef5584
	function model_convert($colour, $from_model, $to_model)
ef5584
	{
ef5584
		if ($from_model == $to_model)
ef5584
		{
ef5584
			return $colour;
ef5584
		}
ef5584
ef5584
		switch ($to_model)
ef5584
		{
ef5584
			case 'hsv':
ef5584
ef5584
				switch ($from_model)
ef5584
				{
ef5584
					case 'ahsv':
ef5584
						return colour_manager::ah2h($colour);
ef5584
					break;
ef5584
ef5584
					case 'rgb':
ef5584
						return colour_manager::rgb2hsv($colour);
ef5584
					break;
ef5584
				}
ef5584
			break;
ef5584
ef5584
			case 'ahsv':
ef5584
ef5584
				switch ($from_model)
ef5584
				{
ef5584
					case 'hsv':
ef5584
						return colour_manager::h2ah($colour);
ef5584
					break;
ef5584
ef5584
					case 'rgb':
ef5584
						return colour_manager::h2ah(colour_manager::rgb2hsv($colour));
ef5584
					break;
ef5584
				}
ef5584
			break;
ef5584
ef5584
			case 'rgb':
ef5584
				switch ($from_model)
ef5584
				{
ef5584
					case 'hsv':
ef5584
						return colour_manager::hsv2rgb($colour);
ef5584
					break;
ef5584
ef5584
					case 'ahsv':
ef5584
						return colour_manager::hsv2rgb(colour_manager::ah2h($colour));
ef5584
					break;
ef5584
				}
ef5584
			break;
ef5584
		}
ef5584
		return false;
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* Slightly altered from wikipedia's algorithm
ef5584
	*/
ef5584
	function hsv2rgb($hsv)
ef5584
	{
ef5584
		colour_manager::normalize_hue($hsv[0]);
ef5584
ef5584
		$h = $hsv[0];
ef5584
		$s = min(1, max(0, $hsv[1] / 100));
ef5584
		$v = min(1, max(0, $hsv[2] / 100));
ef5584
ef5584
		// calculate hue sector
ef5584
		$hi = floor($hsv[0] / 60);
ef5584
ef5584
		// calculate opposite colour
ef5584
		$p = $v * (1 - $s);
ef5584
ef5584
		// calculate distance between hex vertices
ef5584
		$f = ($h / 60) - $hi;
ef5584
ef5584
		// coming in or going out?
ef5584
		if (!($hi & 1))
ef5584
		{
ef5584
			$f = 1 - $f;
ef5584
		}
ef5584
ef5584
		// calculate adjacent colour
ef5584
		$q = $v * (1 - ($f * $s));
ef5584
ef5584
		switch ($hi)
ef5584
		{
ef5584
			case 0:
ef5584
				$rgb = array($v, $q, $p);
ef5584
			break;
ef5584
ef5584
			case 1:
ef5584
				$rgb = array($q, $v, $p);
ef5584
			break;
ef5584
ef5584
			case 2:
ef5584
				$rgb = array($p, $v, $q);
ef5584
			break;
ef5584
ef5584
			case 3:
ef5584
				$rgb = array($p, $q, $v);
ef5584
			break;
ef5584
ef5584
			case 4:
ef5584
				$rgb = array($q, $p, $v);
ef5584
			break;
ef5584
ef5584
			case 5:
ef5584
				$rgb = array($v, $p, $q);
ef5584
			break;
ef5584
ef5584
			default:
ef5584
				return array(0, 0, 0);
ef5584
			break;
ef5584
		}
ef5584
ef5584
		return array(255 * $rgb[0], 255 * $rgb[1], 255 * $rgb[2]);
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* (more than) Slightly altered from wikipedia's algorithm
ef5584
	*/
ef5584
	function rgb2hsv($rgb)
ef5584
	{
ef5584
		$r = min(255, max(0, $rgb[0]));
ef5584
		$g = min(255, max(0, $rgb[1]));
ef5584
		$b = min(255, max(0, $rgb[2]));
ef5584
		$max = max($r, $g, $b);
ef5584
		$min = min($r, $g, $b);
ef5584
ef5584
		$v = $max / 255;
ef5584
		$s = (!$max) ? 0 : 1 - ($min / $max);
ef5584
ef5584
		// if max - min is 0, we want hue to be 0 anyway.
ef5584
		$h = $max - $min;
ef5584
ef5584
		if ($h)
ef5584
		{
ef5584
			switch ($max)
ef5584
			{
ef5584
				case $g:
ef5584
					$h = 120 + (60 * ($b - $r) / $h);
ef5584
				break;
ef5584
ef5584
				case $b:
ef5584
					$h = 240 + (60 * ($r - $g) / $h);
ef5584
				break;
ef5584
ef5584
				case $r:
ef5584
					$h = 360 + (60 * ($g - $b) / $h);
ef5584
				break;
ef5584
			}
ef5584
		}
ef5584
		colour_manager::normalize_hue($h);
ef5584
ef5584
		return array($h, $s * 100, $v * 100);
ef5584
	}
ef5584
ef5584
	/**
ef5584
	*/
ef5584
	function normalize_hue(&$hue)
ef5584
	{
ef5584
		$hue %= 360;
ef5584
ef5584
		if ($hue < 0)
ef5584
		{
ef5584
			$hue += 360;
ef5584
		}
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* Alternate hue to hue
ef5584
	*/
ef5584
	function ah2h($ahue)
ef5584
	{
ef5584
		if (is_array($ahue))
ef5584
		{
ef5584
			$ahue[0] = colour_manager::ah2h($ahue[0]);
ef5584
			return $ahue;
ef5584
		}
ef5584
		colour_manager::normalize_hue($ahue);
ef5584
ef5584
		// blue through red is already ok
ef5584
		if ($ahue >= 240)
ef5584
		{
ef5584
			return $ahue;
ef5584
		}
ef5584
ef5584
		// ahue green is at 180
ef5584
		if ($ahue >= 180)
ef5584
		{
ef5584
			// return (240 - (2 * (240 - $ahue)));
ef5584
			return (2 * $ahue) - 240; // equivalent
ef5584
		}
ef5584
ef5584
		// ahue yellow is at 120   (RYB rather than RGB)
ef5584
		if ($ahue >= 120)
ef5584
		{
ef5584
			return $ahue - 60;
ef5584
		}
ef5584
ef5584
		return $ahue / 2;
ef5584
	}
ef5584
ef5584
	/**
ef5584
	* hue to Alternate hue
ef5584
	*/
ef5584
	function h2ah($hue)
ef5584
	{
ef5584
		if (is_array($hue))
ef5584
		{
ef5584
			$hue[0] = colour_manager::h2ah($hue[0]);
ef5584
			return $hue;
ef5584
		}
ef5584
		colour_manager::normalize_hue($hue);
ef5584
ef5584
		// blue through red is already ok
ef5584
		if ($hue >= 240)
ef5584
		{
ef5584
			return $hue;
ef5584
		}
ef5584
		else if ($hue <= 60)
ef5584
		{
ef5584
			return $hue * 2;
ef5584
		}
ef5584
		else if ($hue <= 120)
ef5584
		{
ef5584
			return $hue + 60;
ef5584
		}
ef5584
		else
ef5584
		{
ef5584
			return ($hue + 240) / 2;
ef5584
		}
ef5584
	}
ef5584
}
ef5584
ef5584
?>