Archive - 2006 - Blog entry

Date
  • All
  • Jan
  • Feb
  • Mar
  • Apr
  • May
  • Jun
  • Jul
  • Aug
  • Sep
  • Oct
  • Nov
  • Dec

Writing an 3D Ray Casting Library for PHP

I was inspired by the 3D Ray Casting game, so I decide to write a 3D ray casting engine myself.
First, I have to create a very simple version that only draw wall with one color. and looks like I failed. I will still work on the ray casting system. Can anyone spot why it looks like this? I think I have to work like about another 12 hours on debugging. :noway:
Initial testing result:
Raycasting test No.1
Here is the source:(no highlighting because it make the server slow... and this code is not important...)

	set_time_limit (5);
//error_reporting(0);
	class raycasting{
	var $pov = array('x' => 5, 'y' => 5, 'z' => 32, 'a' => 190);
	var $scale = 64;
	var $fov = 60;
	var $proj = array('w' =>320, 'h' => 200);
	var $map = '';
	var $cons;
 
	function createmap($map){
		$map = explode("\n",$map);
		$i = 0;
		$count = count($map);
		while($i < $count){
			$map[$i] = explode(' ',$map[$i]);
			++$i;
		}
		$this->map = $map;
		}
 
	function iswall($xy){
//	echo 	'x',$xy['x'],'<br />';
//	echo 	'y',$xy['y'],'<br />';
		if($this->map[floor($xy['x']/$this->scale)][floor($xy['y']/$this->scale)]){
			return true;
	}else{
		return false;
	}
	}
 
	function setup(){
		$this->cons['pov2proj'] = abs(0.5*$this->proj['w']/tan(0.5*$this->fov));
		$this->cons['angleinc'] = $this->fov/$this->proj['w'];
		$this->cons['tri_degree'] = 30;
		$this->proj['x'] = floor($this->proj['w']/2);
		$this->proj['y'] = floor($this->proj['h']/2);
		//find type x and y
		if($this->pov['a'] == 0){
			$this->cons['type']['x'] = 1;
			$this->cons['type']['y'] = 0;
		}elseif($this->pov['a'] == 180){
			$this->cons['type']['x'] = -1;
			$this->cons['type']['y'] = 0;
		}elseif($this->pov['a'] == 90){
			$this->cons['type']['x'] = 0;
			$this->cons['type']['y'] = -1;
		}elseif($this->pov['a'] == 270){
			$this->cons['type']['x'] = 0;
			$this->cons['type']['y'] = 1;
		}elseif(90 > $this->pov['a'] && $this->pov['a'] > 0){
			$this->cons['type']['x'] = 1;
			$this->cons['type']['y'] = -1;
		}elseif(180 > $this->pov['a'] && $this->pov['a'] > 90){
			$this->cons['type']['x'] = -1;
			$this->cons['type']['y'] = -1;
		}elseif(270 > $this->pov['a'] && $this->pov['a'] > 180){
			$this->cons['type']['x'] = -1;
			$this->cons['type']['y'] = 1;
		}else{
			$this->cons['type']['x'] = 1;
			$this->cons['type']['y'] = 1;
		}
	}
 
function render(){
	$i = 0;
	while($i < $this->proj['w']){
		//find the x intersect
		//find the y coordinate for the first intersect
		if($this->cons['type']['x'] == 0){
			if($this->cons['type']['y'] == 1){
				$x_intersect['y'] = cell($this->pov['y']/$this->scale)*$this->scale;
			}else{
				$x_intersect['y'] = floor($this->pov['y']/$this->scale)*$this->scale;
			}
		}else{
			if($this->cons['type']['y'] == 1){
				$x_intersect['y'] = floor($this->pov['y']/$this->scale)*$this->scale+$this->scale;
			}else{
				$x_intersect['y'] = floor($this->pov['y']/$this->scale)*$this->scale-1;
			}
		}
		//find the x coordinate of first intersect
		$x_intersect['x'] = floor($this->pov['x'] + ($this->pov['y'] - $x_intersect['y'])/tan($this->cons['tri_degree']));
		//check if it is wall
		if(!$this->iswall($x_intersect)){
			//the loop for intersect that touches the wall
			$y_add = $this->scale * $this->cons['type']['y'];
			$x_add = floor($this->scale/tan($this->cons['tri_degree']));
			while(!$this->iswall($x_intersect)){
				$x_intersect['x'] += $x_add;
				$x_intersect['y'] += $y_add;
			}
		}
 
 
 
 
		//FIND THE Y_INTERSECT THAT TOUCHES A WALL
		//find the y coordinate for the first intersect
		if($this->cons['type']['y'] == 0){
			if($this->cons['type']['x'] == 1){
				$y_intersect['x'] = cell($this->pov['x']/$this->scale)*$this->scale;
 
			}else{
				$y_intersect['x'] = floor($this->pov['x']/$this->scale)*$this->scale;
			}
		}else{
			if($this->cons['type']['x'] == 1){
				$y_intersect['x'] = cell($this->pov['x']/$this->scale)*$this->scale+$this->scale;
 
			}else{
				$y_intersect['x'] = floor($this->pov['x']/$this->scale)*$this->scale-1;
				if($y_intersect['x'] < 0){
					$y_intersect['x'] = 0;
				}
			}
		}
		//find the x coordinate of first intersect
		$y_intersect['y'] = floor($this->pov['y'] + ($this->pov['x'] - $x_intersect['x'])/tan($this->cons['tri_degree']));
		//check if it is wall
		if(!$this->iswall($y_intersect)){
			//the loop for intersect that touches the wall
			$x_add = $this->scale * $this->cons['type']['x'];
			$y_add = floor($this->scale/tan($this->cons['tri_degree']));
			while(!$this->iswall($x_intersect)){
				$y_intersect['x'] += $x_add;
				$y_intersect['y'] += $y_add;
			}
		}
 
		$x_intersect['distance'] = sqrt(pow($this->pov['x']-$x_intersect['x'],2)+pow($this->pov['y']-$x_intersect['y'],2));
		$y_intersect['distance'] = sqrt(pow($this->pov['x']-$y_intersect['x'],2)+pow($this->pov['y']-$y_intersect['y'],2));
		if($x_intersect['distance']<$y_intersect['distance']){
			$distance[$i]['d'] = $x_intersect['distance'];
			$distance[$i]['c'] = 'x';
		}else{
			$distance[$i]['d'] = $y_intersect['distance'];
			$distance[$i]['c'] = 'y';
		}
		++$i;
	}
 
	//remove distortion
	$i = 0;
	$half_fov = $this->fov / 2;
	while($i<$this->proj['x']){
		$product = cos(($this->proj['x']-$i) * $this->cons['angleinc']);
		$distance[$i]['d'] *= $product;
		$distance[$i+$proj['x']]['d'] *= $product;
		++$i;
	}
 
	$product = $this->scale/$this->cons['pov2proj'];
	$i = 0;
	while($i<$this->proj['w']){
		$proj_height[$i] = $product/$distance[$i]['d'];
		++$i;
	}
	//image creation
	$image = imagecreate($this->proj['w'], $this->proj['h']);
	//color
	$god = imagecolorallocate($image, 0xC0, 0xC0, 0xC0);
	$color = imagecolorallocate($image, 0xFF, 0xFF, 0xFF);
	$color2 = imagecolorallocate($image, 0x00, 0x00, 0x00);
	//draw wall
	$i = 0;
	while($i < $this->proj['w']){
		$start_y = ($this->proj['h'] - $proj_height[$i])/2;
		imageline($image, $i+1, $start_y, $i+1, $start_y+$proj_height[$i], $color);
		++$i;
	}
header('Content-type: image/png');
header('Content-Length: ' . strlen($img));
	imagepng($image);
}
	}
 
$modle = new raycasting;
$map = 
"1 1 1 1 1 1
1 0 0 0 0 1
1 0 0 0 0 1
1 0 1 1 0 1
1 1 1 1 1 1";
$modle->createmap($map);
$modle->setup();
$modle->render();

Chess widget that uses AJAX to retrieve chess data

Chess Widget is like jsPgnViewer, but it's more Ajax. It retrieve chess data from the server and show the game dynamically.

Chess widget

Image_Turtle

Image_Turtle is a image drawing system work with Lindenmayer system. It is made by Kore Nordmann, one of the lead of the Image_3D project. The class is called turtle is because the line drawing item is referred as turtle, like the one in the Logo programming language.
The tree below is generated by this code:

require_once 'Image/Turtle/Memory.php';
$turtle = new Image_Turtle_Memory(array(310, 590), -90);
 
// Configure turtle
$turtle->step = 130; // Width of step forward
$turtle->a = 25; // Angle
$turtle->s = .25; // Buckling
 
// Create and execute the "programm"
$turtle->addRule('w', 'FFF[+F+F+F][-F+F+F+F+F]');
$turtle->addRule('F', 'FFF[+F+F+F][-F+F+F+F+F]');
 
$turtle->setStartRule('w');
 
$turtle->process(3);
 
// Render output
$turtle->render(400, 600, 'tree.png');

Turtle Tree
Here is another image by Image_Turtle
Turtle Standard

Editor Comment:

Kore Nordmann have done a lot of work on image generation. Anyone who wants try out Logo, check out the Logo Class in PHP

debugConsole

debugConsole is a powerful debug system for PHP that maintains by Andreas Demmer. It's written completely in PHP and work as a class, not like Xdebug, which is an extension to PHP. With debugConsole, error handling and variable change tracking is taken care of.

debugConsole screenshot

Editor Comment:

If the native variable dump function in debugConsole are as good as dBug , this might be the tool of choice for all developers.

Tango Desktop Project

Tango is a library full of icons available in SVG and other format. use SVG means the icons can be resize to any size and lose no information.

Tango Icons

Honey Pot that kill bots