mirror of
https://github.com/lubosz/overte.git
synced 2025-04-05 22:02:37 +02:00
860 lines
23 KiB
PHP
860 lines
23 KiB
PHP
<?php
|
|
// Parse/Read OBJ file
|
|
//
|
|
// USAGE: php objtohio.php -i 'inputFileName' -o 'outputFileName' -m [blocks|wireframe|surface] -s [voxel size]
|
|
// NOTE: Depending on the size of the model, it might take a lot of memory, so you will likely need to include
|
|
// the -d memory_limit=4096M option
|
|
//
|
|
global $lastmsg;
|
|
$lastmsg='';
|
|
|
|
function echoProgress($msg,$keep=false) {
|
|
global $lastmsg;
|
|
for($bs=0;$bs<strlen($lastmsg);$bs++) {
|
|
echo chr(8);
|
|
}
|
|
for($bs=0;$bs<strlen($lastmsg);$bs++) {
|
|
echo ' ';
|
|
}
|
|
for($bs=0;$bs<strlen($lastmsg);$bs++) {
|
|
echo chr(8);
|
|
}
|
|
echo $msg;
|
|
if (!$keep)
|
|
$lastmsg=$msg;
|
|
else
|
|
$lastmsg='';
|
|
}
|
|
|
|
|
|
class Vertice
|
|
{
|
|
public $x;
|
|
public $y;
|
|
public $z;
|
|
}
|
|
|
|
class Voxel
|
|
{
|
|
public $material_name;
|
|
public $x;
|
|
public $y;
|
|
public $z;
|
|
public $s;
|
|
}
|
|
|
|
global $renderMode;
|
|
$renderMode = 'surface';
|
|
|
|
global $minVoxelSize;
|
|
$minVoxelSize = 0.003; // default
|
|
|
|
function findVoxelsOfPolygon($vertices,$s=false,$material='default') {
|
|
//echo "findVoxelsOfPolygon() vertices=".print_r($vertices,1);
|
|
|
|
global $renderMode;
|
|
switch ($renderMode)
|
|
{
|
|
case 'blocks':
|
|
return polygonAsBlocks($vertices,$s,$material);
|
|
case 'wireframe':
|
|
//echo "findVoxelsOfPolygon() calling... polygonAsWireFrame() vertices=".print_r($vertices,1);
|
|
return polygonAsWireFrame($vertices,$s,$material);
|
|
default:
|
|
case 'surface':
|
|
return polygonAsSurface($vertices,$s,$material);
|
|
}
|
|
}
|
|
|
|
function polygonAsWireFrame($vertices,$s=false,$material='default')
|
|
{
|
|
if ($s === false) {
|
|
global $minVoxelSize;
|
|
$s = $minVoxelSize;
|
|
}
|
|
//echo "polygonAsWireFrame()\n";
|
|
//echo "polygonAsWireFrame() vertices=".print_r($vertices,1);
|
|
|
|
$maxNdx = count($vertices);
|
|
//echo "***** polygonAsWireFrame() maxNdx=$maxNdx\n";
|
|
$voxels = array();
|
|
for ($ndx = 0; $ndx < $maxNdx; $ndx++)
|
|
{
|
|
$v1 = $vertices[$ndx];
|
|
$v2 = ($ndx < ($maxNdx-1)) ? $vertices[$ndx+1] : $vertices[0];
|
|
$lineVoxels = voxelLine($v1->x,$v1->y,$v1->z,$v2->x,$v2->y,$v2->z,$s,$material);
|
|
//echo "polygonAsWireFrame() lineVoxels=".print_r($lineVoxels,1);
|
|
$voxels = array_merge($voxels,$lineVoxels);
|
|
}
|
|
return $voxels;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
// Find the smallest Voxel of a random polygon.
|
|
// find minimums of X,Y,Z
|
|
// find maximums of X,Y,Z
|
|
// find lengths of max-mins for X,Y,Z
|
|
// Voxel Point = (minX, minY, minZ,longest side)
|
|
function polygonAsBlocks($vertices,$s=false,$material='default')
|
|
{
|
|
if ($s === false) {
|
|
global $minVoxelSize;
|
|
$s = $minVoxelSize;
|
|
}
|
|
|
|
//echo "polygonAsBlocks()\n";
|
|
$minX = false;
|
|
$minY = false;
|
|
$minZ = false;
|
|
$maxX = false;
|
|
$maxY = false;
|
|
$maxZ = false;
|
|
foreach ($vertices as $vertex)
|
|
{
|
|
if ($minX === false || $vertex->x < $minX)
|
|
$minX = $vertex->x;
|
|
|
|
if ($minY === false || $vertex->y < $minY)
|
|
$minY = $vertex->y;
|
|
|
|
if ($minZ === false || $vertex->z < $minZ)
|
|
$minZ = $vertex->z;
|
|
|
|
if ($maxX === false || $vertex->x > $maxX)
|
|
$maxX = $vertex->x;
|
|
|
|
if ($maxY === false || $vertex->y > $maxY)
|
|
$maxY = $vertex->y;
|
|
|
|
if ($maxZ === false || $vertex->z > $maxZ)
|
|
$maxZ = $vertex->z;
|
|
}
|
|
$longestSide = max($maxX-$minX,$maxY-$minY,$maxZ-$minZ);
|
|
$shortestSide = max(0.0005,min($maxX-$minX,$maxY-$minY,$maxZ-$minZ));
|
|
|
|
//printf("findVoxelsOfPolygon() shortestSide=$shortestSide\n");
|
|
//printf("findVoxelsOfPolygon() minX=$minX, maxX=$maxX\n");
|
|
//printf("findVoxelsOfPolygon() minY=$minY, maxY=$maxY\n");
|
|
//printf("findVoxelsOfPolygon() minZ=$minZ, maxZ=$maxZ\n");
|
|
|
|
$voxels = array();
|
|
// Could we???
|
|
// use the shortest side as our voxel unit, and build up
|
|
// the partial volume from those blocks....???
|
|
$x = $minX;
|
|
while ($x <= $maxX)
|
|
{
|
|
//printf("findVoxelsOfPolygon() X loop x=$x, y=$y, z=$z\n");
|
|
$y = $minY;
|
|
while($y <= $maxY)
|
|
{
|
|
//printf("findVoxelsOfPolygon() x=$x, y=$y, z=$z\n");
|
|
$z = $minZ;
|
|
while ($z <= $maxZ)
|
|
{
|
|
//printf("findVoxelsOfPolygon() x=$x, y=$y, z=$z, shortestSide=$shortestSide\n");
|
|
$voxel = new Voxel();
|
|
$voxel->x = (float)$x;
|
|
$voxel->y = (float)$y;
|
|
$voxel->z = (float)$z;
|
|
$voxel->s = (float)$shortestSide;
|
|
$voxels[]=$voxel;
|
|
|
|
$z+=$shortestSide;
|
|
}
|
|
$y+=$shortestSide;
|
|
}
|
|
$x+=$shortestSide;
|
|
}
|
|
return $voxels;
|
|
}
|
|
|
|
// $scaleU is the scale in universal coordinates that the voxels will
|
|
// be scaled to fill. we use 1 by default
|
|
function rescaleVoxels($voxels,$scaleU=1)
|
|
{
|
|
echo "rescaleVoxels()...\n";
|
|
$minX = false;
|
|
$minY = false;
|
|
$minZ = false;
|
|
$maxX = false;
|
|
$maxY = false;
|
|
$maxZ = false;
|
|
|
|
$vc=0;
|
|
|
|
foreach ($voxels as $voxel)
|
|
{
|
|
$vc++;
|
|
echoProgress("searching for bounds voxel:$vc");
|
|
|
|
//print_r($voxel);
|
|
if ($minX === false || $voxel->x < $minX)
|
|
{
|
|
//echo "found new minX!\n";
|
|
$minX = $voxel->x;
|
|
}
|
|
|
|
if ($minY === false || $voxel->y < $minY)
|
|
{
|
|
//echo "found new miny!\n";
|
|
$minY = $voxel->y;
|
|
}
|
|
|
|
if ($minZ === false || $voxel->z < $minZ)
|
|
{
|
|
//echo "found new minZ!\n";
|
|
$minZ = $voxel->z;
|
|
}
|
|
|
|
if ($maxX === false || ($voxel->x+$voxel->s) > $maxX)
|
|
{
|
|
$maxX = ($voxel->x+$voxel->s);
|
|
}
|
|
|
|
if ($maxY === false || ($voxel->y+$voxel->s) > $maxY)
|
|
{
|
|
//echo "found new maxY!\n";
|
|
$maxY = ($voxel->y+$voxel->s);
|
|
}
|
|
|
|
if ($maxZ === false || ($voxel->z+$voxel->s) > $maxZ)
|
|
{
|
|
//echo "found new maxZ!\n";
|
|
$maxZ = ($voxel->z+$voxel->s);
|
|
}
|
|
}
|
|
echoProgress("Done searching for bounds...\n",true);
|
|
|
|
echo "minX=$minX, minY=$minY, minZ=$minZ\n";
|
|
echo "maxX=$maxX, maxY=$maxY, maxZ=$maxZ\n";
|
|
$widthX = $maxX-$minX;
|
|
$widthY = $maxY-$minY;
|
|
$widthZ = $maxZ-$minZ;
|
|
$widthU = max($widthX,$widthY,$widthZ);
|
|
|
|
echo "widthX=$widthX, widthY=$widthY, widthZ=$widthZ, widthU=$widthU\n";
|
|
|
|
$vc=0;
|
|
foreach ($voxels as $voxel)
|
|
{
|
|
$vc++;
|
|
echoProgress("Scaling voxel:$vc");
|
|
|
|
$voxel->x = $widthX ? (($voxel->x - $minX)/$widthU)*$scaleU : 0;
|
|
$voxel->y = $widthY ? (($voxel->y - $minY)/$widthU)*$scaleU : 0;
|
|
$voxel->z = $widthZ ? (($voxel->z - $minZ)/$widthU)*$scaleU : 0;
|
|
$voxel->s = ($voxel->s/$widthU)*$scaleU;
|
|
}
|
|
echoProgress("Done Rescaling Voxels!\n",true);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
// Function: voxelPolygon()
|
|
// Description: Given an array of universal points forming a polygon in 3D space, this
|
|
// will return an array of voxels that fill the interior of this polygon
|
|
// The voxels will match size s. The input values x,y,z range 0.0 <= v < 1.0
|
|
// To Do: Currently, this will only work on convex polygons. If the polygon is
|
|
// concave, we need to partition it into smaller convex polygons.
|
|
// Complaints: Brad :)
|
|
function polygonAsSurface($vertices,$s=false,$material='default') {
|
|
|
|
if ($s === false) {
|
|
global $minVoxelSize;
|
|
$s = $minVoxelSize;
|
|
}
|
|
|
|
//echo "polygonAsSurface()\n";
|
|
//echoProgress("polygonAsSurface()");
|
|
|
|
|
|
//echo "polygonAsSurface() vertices=".print_r($vertices,1);
|
|
|
|
$voxels = array();
|
|
// starting at v[1]
|
|
// for each vertice v
|
|
// for N over v[v+1] to v[v+2]
|
|
// draw a line from v to v[v+1~v+2:N]
|
|
// NOTE: this will result in several overlapping/duplicate voxels, so discard extras!!
|
|
// ALSO NOTE: this will only work on convex polygons.
|
|
// If the polygon is concave, we need to partition it into smaller convex polygons
|
|
$count = count($vertices);
|
|
$vO = $vertices[0];
|
|
//echo "polygonAsSurface() count=$count\n";
|
|
//echo "polygonAsSurface() vO=".print_r($vO,1);
|
|
|
|
for($n = 1; $n < $count; $n++)
|
|
{
|
|
$nP1 = ($n+1)%$count;
|
|
//echo "polygonAsSurface() n=$n nP1=$nP1\n";
|
|
|
|
$vA = $vertices[$n];
|
|
$vB = $vertices[$nP1];
|
|
|
|
//echo "polygonAsSurface() vA=".print_r($vA,1);
|
|
//echo "polygonAsSurface() vB=".print_r($vB,1);
|
|
|
|
//echo "polygonAsSurface() ... voxelLine({$vA->x},{$vA->y},{$vA->z},{$vB->x},{$vB->y},{$vB->z},$s,$material)\n";
|
|
|
|
$lAB = voxelLine($vA->x,$vA->y,$vA->z,$vB->x,$vB->y,$vB->z,$s,$material);
|
|
|
|
//echo "**** polygonAsSurface() count(lAB)=".count($lAB)."\n";
|
|
|
|
$lc=0;
|
|
foreach($lAB as $vAB)
|
|
{
|
|
//echo ">>> polygonAsSurface() vAB=".print_r($vAB,1);
|
|
//echo ">>> polygonAsSurface() ... voxelLine({$vO->x},{$vO->y},{$vO->z},{$vAB->x},{$vAB->y},{$vAB->z},$s,$material)\n";
|
|
|
|
$lOAB = voxelLine($vO->x,$vO->y,$vO->z,$vAB->x,$vAB->y,$vAB->z,$s,$material);
|
|
$lc++;
|
|
//echoProgress("polygonAsSurface()... voxelLine() $lc");
|
|
|
|
//echo ">>> polygonAsSurface() count(lOAB)=".count($lOAB)."\n";
|
|
$voxels = array_merge($voxels,$lOAB);
|
|
}
|
|
}
|
|
//echo "polygonAsSurface() count(voxels)=".count($voxels)."\n";
|
|
//echoProgress("polygonAsSurface() count(voxels)=".count($voxels));
|
|
return $voxels;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
// Function: voxelLine()
|
|
// Description: Given two universal points with location x1,y1,z1 and x2,y2,z2 this will
|
|
// return an array of voxels that connect these two points with a straight
|
|
// line. The voxels will match size s.
|
|
// The input values x,y,z range 0.0 <= v < 1.0
|
|
// Complaints: Brad :)
|
|
function voxelLine($x1,$y1,$z1,$x2,$y2,$z2,$s,$material='default')
|
|
{
|
|
$voxels = array();
|
|
$xV = $x2-$x1;
|
|
$yV = $y2-$y1;
|
|
$zV = $z2-$z1;
|
|
$mV = max(abs($xV),abs($yV),abs($zV)); // max vector, which is the one we'll iterate accoss!
|
|
$its = round($mV/$s);
|
|
|
|
/**
|
|
echo "voxelLine() xV=$xV\n";
|
|
echo "voxelLine() yV=$yV\n";
|
|
echo "voxelLine() zV=$zV\n";
|
|
echo "voxelLine() mV=$mV\n";
|
|
echo "voxelLine() its=$its\n";
|
|
**/
|
|
|
|
for ($i = 0; $i < $its; $i++)
|
|
{
|
|
//echo "voxelLine() loop i=$i\n";
|
|
$x = $x1+(($xV/$its)*$i);
|
|
$y = $y1+(($yV/$its)*$i);
|
|
$z = $z1+(($zV/$its)*$i);
|
|
$voxel = new Voxel();
|
|
$voxel->x=$x;
|
|
$voxel->y=$y;
|
|
$voxel->z=$z;
|
|
$voxel->s=$s;
|
|
$voxel->material_name=$material;
|
|
$voxels[] = $voxel;
|
|
}
|
|
return $voxels;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
// Function: pointToVoxel()
|
|
// Description: Given a universal point with location x,y,z this will return the voxel
|
|
// voxel code corresponding to the closest voxel which encloses a cube with
|
|
// lower corners at x,y,z, having side of length S.
|
|
// The input values x,y,z range 0.0 <= v < 1.0
|
|
// TO DO: This code is not very DRY. It should be cleaned up to be DRYer.
|
|
// IMPORTANT: The voxel is returned to you a buffer which you MUST delete when you are
|
|
// done with it.
|
|
// Usage:
|
|
// unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue);
|
|
// tree->readCodeColorBufferToTree(voxelData);
|
|
// delete voxelData;
|
|
//
|
|
// Complaints: Brad :)
|
|
global $maxOctet,$minOctet;
|
|
$maxOctet=0;
|
|
$minOctet=100;
|
|
function pointToVoxel($x,$y,$z,$s,$r=false,$g=false,$b=false)
|
|
{
|
|
$xTest = $yTest = $zTest = $sTest = 0.5;
|
|
|
|
// First determine the voxelSize that will properly encode a
|
|
// voxel of size S.
|
|
$voxelSizeInBits = 0;
|
|
while ($sTest > $s) {
|
|
$sTest /= 2.0;
|
|
$voxelSizeInBits+=3;
|
|
}
|
|
|
|
$voxelSizeInBytes = round(($voxelSizeInBits/8)+1);
|
|
$voxelSizeInOctets = round($voxelSizeInBits/3);
|
|
$voxelBufferSize = $voxelSizeInBytes+1+3; // 1 for size, 3 for color
|
|
|
|
if ($voxelSizeInOctets < 1)
|
|
{
|
|
echo "************ WTH!! voxelSizeInOctets=$voxelSizeInOctets s=$s sTest=$sTest ************\n";
|
|
}
|
|
|
|
// for debugging, track our largest octet
|
|
global $maxOctet,$minOctet;
|
|
//echo "voxelSizeInOctets=$voxelSizeInOctets\n";
|
|
$maxOctet = max($maxOctet,$voxelSizeInOctets);
|
|
$minOctet = min($minOctet,$voxelSizeInOctets);
|
|
if ($minOctet < 1)
|
|
{
|
|
echo "************ WTH!! minOctet=$minOctet\n";
|
|
}
|
|
//echo "maxOctet=$maxOctet\n";
|
|
|
|
// allocate our resulting buffer
|
|
$voxelOut = array();
|
|
|
|
// first byte of buffer is always our size in octets
|
|
$voxelOut[0]=$voxelSizeInOctets;
|
|
|
|
$sTest = 0.5; // reset sTest so we can do this again.
|
|
|
|
$byte = 0; // we will be adding coding bits here
|
|
$bitInByteNDX = 0; // keep track of where we are in byte as we go
|
|
$byteNDX = 1; // keep track of where we are in buffer of bytes as we go
|
|
$octetsDone = 0;
|
|
|
|
// Now we actually fill out the voxel code
|
|
while ($octetsDone < $voxelSizeInOctets) {
|
|
|
|
//echo "coding octet: octetsDone=$octetsDone voxelSizeInOctets=$voxelSizeInOctets\n";
|
|
|
|
if ($x > $xTest) {
|
|
//<write 1 bit>
|
|
$byte = ($byte << 1) | true;
|
|
$xTest += $sTest/2.0;
|
|
}
|
|
else {
|
|
//<write 0 bit;>
|
|
$byte = ($byte << 1) | false;
|
|
$xTest -= $sTest/2.0;
|
|
}
|
|
$bitInByteNDX++;
|
|
// If we've reached the last bit of the byte, then we want to copy this byte
|
|
// into our buffer. And get ready to start on a new byte
|
|
if ($bitInByteNDX > 7)
|
|
{
|
|
//printf("xTest: got 8 bits, write to array byteNDX=$byteNDX byte=[%08b]\n",$byte);
|
|
$voxelOut[$byteNDX]=$byte;
|
|
$byteNDX += 1;
|
|
$bitInByteNDX=0;
|
|
$byte=0;
|
|
}
|
|
|
|
if ($y > $yTest) {
|
|
//<write 1 bit>
|
|
$byte = ($byte << 1) | true;
|
|
$yTest += $sTest/2.0;
|
|
}
|
|
else {
|
|
//<write 0 bit;>
|
|
$byte = ($byte << 1) | false;
|
|
$yTest -= $sTest/2.0;
|
|
}
|
|
$bitInByteNDX++;
|
|
//echo "coding octet: octetsDone=$octetsDone voxelSizeInOctets=$voxelSizeInOctets bitInByteNDX=$bitInByteNDX\n";
|
|
|
|
// If we've reached the last bit of the byte, then we want to copy this byte
|
|
// into our buffer. And get ready to start on a new byte
|
|
if ($bitInByteNDX > 7)
|
|
{
|
|
//printf("yTest: got 8 bits, write to array byteNDX=$byteNDX byte=[%08b]\n",$byte);
|
|
$voxelOut[$byteNDX]=$byte;
|
|
$byteNDX += 1;
|
|
$bitInByteNDX=0;
|
|
$byte=0;
|
|
}
|
|
|
|
if ($z > $zTest) {
|
|
//<write 1 bit>
|
|
$byte = ($byte << 1) | true;
|
|
$zTest += $sTest/2.0;
|
|
}
|
|
else {
|
|
//<write 0 bit;>
|
|
$byte = ($byte << 1) | false;
|
|
$zTest -= $sTest/2.0;
|
|
}
|
|
$bitInByteNDX++;
|
|
// If we've reached the last bit of the byte, then we want to copy this byte
|
|
// into our buffer. And get ready to start on a new byte
|
|
if ($bitInByteNDX > 7)
|
|
{
|
|
//printf("zTest: got 8 bits, write to array byteNDX=$byteNDX byte=[%08b]\n",$byte);
|
|
$voxelOut[$byteNDX]=$byte;
|
|
$byteNDX += 1;
|
|
$bitInByteNDX=0;
|
|
$byte=0;
|
|
}
|
|
|
|
$octetsDone++;
|
|
$sTest /= 2.0;
|
|
}
|
|
|
|
//printf("done with bits: byteNDX=$byteNDX bitInByteNDX=$bitInByteNDX\n");
|
|
|
|
// If we've got here, and we didn't fill the last byte, we need to zero pad this
|
|
// byte before we copy it into our buffer.
|
|
if ($bitInByteNDX > 0 && $bitInByteNDX < 8)
|
|
{
|
|
// Pad the last byte
|
|
while ($bitInByteNDX <= 7)
|
|
{
|
|
$byte = ($byte << 1) | false;
|
|
$bitInByteNDX++;
|
|
}
|
|
|
|
// Copy it into our output buffer
|
|
//printf("padding: array byteNDX=$byteNDX byte=[%08b]\n",$byte);
|
|
$voxelOut[$byteNDX]=$byte;
|
|
$byteNDX += 1;
|
|
}
|
|
// copy color data
|
|
if ($r !== false)
|
|
{
|
|
//printf("color: array byteNDX=$byteNDX red=$r [%08b] green=$g [%08b] blue=$b [%08b]\n",$r,$g,$b);
|
|
}
|
|
$voxelOut[$byteNDX]=$r;
|
|
$voxelOut[$byteNDX+1]=$g;
|
|
$voxelOut[$byteNDX+2]=$b;
|
|
|
|
return $voxelOut;
|
|
}
|
|
|
|
function dumpVoxelCode($voxelCode)
|
|
{
|
|
foreach($voxelCode as $byte)
|
|
{
|
|
printf("[%08b]",$byte);
|
|
}
|
|
echo "\n";
|
|
}
|
|
|
|
class Material
|
|
{
|
|
public $name;
|
|
public $red;
|
|
public $green;
|
|
public $blue;
|
|
}
|
|
|
|
function randomColorValue($miniumum) {
|
|
return $miniumum + (rand() % (255 - $miniumum));
|
|
}
|
|
|
|
global $all_voxels;
|
|
global $all_voxel_codes;
|
|
|
|
$all_voxels = array();
|
|
function add_voxels($voxels)
|
|
{
|
|
global $all_voxels;
|
|
// users can pass an array or a single voxel,
|
|
// we're rather work on arrays, so conver a single
|
|
// voxel into an array
|
|
if (!is_array($voxels))
|
|
{
|
|
$voxels = array($voxels);
|
|
}
|
|
|
|
//echo "add_voxels()...".print_r($voxels,1);
|
|
|
|
foreach ($voxels as $voxel)
|
|
{
|
|
// we ignore color here!
|
|
$voxelCode = pointToVoxel($voxel->x,$voxel->y,$voxel->z,$voxel->s,false,false,false);
|
|
$voxelCode = implode(',',$voxelCode);
|
|
$all_voxels[$voxelCode]=$voxel;
|
|
}
|
|
// echo "all_voxels count=".count($all_voxels)."\n";
|
|
}
|
|
|
|
|
|
function convertObjFile($inputFileName,$outputFileName)
|
|
{
|
|
$inputFile = fopen($inputFileName, "rt"); // these are text files
|
|
|
|
$fCount=0;
|
|
|
|
$default_material = new Material();
|
|
$default_material->name = 'default';
|
|
$default_material->red = 240;
|
|
$default_material->green = 240;
|
|
$default_material->blue = 240;
|
|
$current_material = $default_material;
|
|
$materials = Array('default'=>$default_material);
|
|
|
|
$vertices = Array();
|
|
$voxels = Array();
|
|
|
|
// Note: AFAIK we can't be certain that all the vertices are included
|
|
// at the start of the file before faces. So we need:
|
|
// 1) scan the entire file, and pull out all the vertices.
|
|
// 2) Then we can resample that set of vertices to match our coordinate system.
|
|
// 3) THEN we can process the faces to make voxels
|
|
$filePasses = array('v','f');
|
|
$commands = array('v'=>array('v','f','fill_from'),'f'=>array('f','usemtl','material'));
|
|
foreach ($filePasses as $pass)
|
|
{
|
|
fseek($inputFile,0); // always rewind at the start of each pass
|
|
// Before we do the face pass, resample the vertices
|
|
if ($pass == 'f')
|
|
{
|
|
// now we actually need to rescale our voxels to fit in a 0-1 coordinate space
|
|
|
|
echo "vertices PRE-rescale:\n";
|
|
//print_r($vertices);
|
|
|
|
rescaleVoxels($vertices);
|
|
|
|
echo "vertices POST-rescale:\n";
|
|
//print_r($vertices);
|
|
}
|
|
|
|
while (!feof($inputFile) )
|
|
{
|
|
$line_of_text = fgets($inputFile);
|
|
$line_of_text = ereg_replace('[[:blank:]]+', ' ', $line_of_text);
|
|
$line_of_text = trim(str_replace('\n', '', $line_of_text));
|
|
|
|
//echo "$line_of_text";
|
|
$parts = explode(' ', $line_of_text);
|
|
$cmd = $parts[0];
|
|
|
|
if (in_array($cmd,$commands[$pass]))
|
|
{
|
|
switch ($cmd)
|
|
{
|
|
// Note: fill from
|
|
case 'fill_from':
|
|
// a vertice
|
|
$v = new Vertice();
|
|
$v->x = (float)$parts[1];
|
|
$v->y = (float)$parts[2];
|
|
$v->z = (float)$parts[3];
|
|
$vertices[] = $v;
|
|
//echo "vertice: ".sizeof($vertices)."\n";
|
|
//echo " vertice:".print_r($v,1)."\n";
|
|
break;
|
|
|
|
case 'v':
|
|
// a vertice
|
|
$v = new Vertice();
|
|
$v->x = (float)$parts[1];
|
|
$v->y = (float)$parts[2];
|
|
$v->z = (float)$parts[3];
|
|
$vertices[] = $v;
|
|
|
|
//echo "vertice: ".sizeof($vertices)."\n";
|
|
|
|
//echo " vertice:".print_r($v,1)."\n";
|
|
|
|
break;
|
|
|
|
case 'material':
|
|
// material group...
|
|
$material_name = trim($parts[1]);
|
|
$red = $parts[2];
|
|
$green = $parts[3];
|
|
$blue = $parts[4];
|
|
echoProgress("material definition: {$material_name} $red $green $blue\n");
|
|
|
|
if (!in_array($material,$materials))
|
|
{
|
|
$material = new Material();
|
|
}
|
|
else
|
|
{
|
|
$material = $materials[$material_name];
|
|
}
|
|
|
|
$material->name = $material_name;
|
|
$material->red = $red;
|
|
$material->green = $green;
|
|
$material->blue = $blue;
|
|
$materials[$material_name]=$material;
|
|
break;
|
|
|
|
case 'usemtl':
|
|
// material group...
|
|
$material = trim($parts[1]);
|
|
echoProgress("usemtl: {$material}\n");
|
|
|
|
if (!isset($materials[$material]))
|
|
{
|
|
echoProgress("material: {$material} generating random colors...\n");
|
|
$new_material = new Material();
|
|
$new_material->name = $material;
|
|
$new_material->red = randomColorValue(65);
|
|
$new_material->green = randomColorValue(65);
|
|
$new_material->blue = randomColorValue(65);
|
|
$materials[$material]=$new_material;
|
|
}
|
|
$current_material = $materials[$material];
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
if ($pass=='v')
|
|
{
|
|
$ftCount++;
|
|
}
|
|
else
|
|
{
|
|
// a face!
|
|
$fCount++;
|
|
$percentComplete = sprintf("%.2f%%",($fCount/$ftCount)*100);
|
|
echoProgress("face processing: $fCount of $ftCount {$percentComplete}");
|
|
|
|
$verticeCount = sizeof($parts) - 1;
|
|
$faceVertices = Array();
|
|
for ($i = 1; $i <= $verticeCount; $i++)
|
|
{
|
|
$vdata = $parts[$i];
|
|
$vdataParts = explode('/',$vdata);
|
|
$vref = $vdataParts[0]-1; // indexes in files are 1 based
|
|
$actualVertice = $vertices[$vref];
|
|
$faceVertices[] = $actualVertice;
|
|
}
|
|
|
|
//echo "face: $fCount material:{$current_material->name}\n";
|
|
|
|
//echo " face:".print_r($faceVertices,1)."\n";
|
|
$voxelsOfPolygon = findVoxelsOfPolygon($faceVertices);
|
|
|
|
//echo "face: $fCount sizeof(voxelOfPolygon)=".sizeof($voxelsOfPolygon)."\n";
|
|
|
|
foreach ($voxelsOfPolygon as $voxel)
|
|
{
|
|
$voxel->material_name = $current_material->name;
|
|
add_voxels($voxel);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// something we don't currently recognize or care about.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fclose($inputFile);
|
|
|
|
// Now that we've made our object. We need to fill it in...
|
|
|
|
|
|
if ($outputFileName)
|
|
{
|
|
$outputFile = fopen($outputFileName,'wb');
|
|
|
|
$vCount = 0;
|
|
global $all_voxels;
|
|
$vtCount = sizeof($all_voxels);
|
|
foreach ($all_voxels as $voxel)
|
|
{
|
|
$vCount++;
|
|
|
|
$percentComplete = sprintf("%.2f%%",($vCount/$vtCount)*100);
|
|
echoProgress("writing file: $vCount of $vtCount {$percentComplete}");
|
|
|
|
|
|
$material = $materials[$voxel->material_name];
|
|
$r = $material->red;
|
|
$g = $material->green;
|
|
$b = $material->blue;
|
|
//echo "v:$vCount: starting \n";
|
|
$voxelCode = pointToVoxel($voxel->x,$voxel->y,$voxel->z,$voxel->s,$r,$g,$b);
|
|
//print_r($voxel);
|
|
//echo "v:$vCount: (".sizeof($voxelCode).") ";
|
|
//dumpVoxelCode($voxelCode);
|
|
|
|
// if we were given an output filename, then write to it.
|
|
if ($outputFile)
|
|
{
|
|
//echo "voxel code size:".sizeof($voxelCode)."\n";
|
|
foreach($voxelCode as $byte)
|
|
{
|
|
$packedByte = pack('C',$byte);
|
|
fwrite($outputFile,$packedByte,1);
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose($outputFile);
|
|
}
|
|
|
|
echo "\n*******\n";
|
|
echo "Total Vertices: ".sizeof($vertices)."\n";
|
|
echo "Total Voxels: ".sizeof($all_voxels)."\n";
|
|
global $maxOctet,$minOctet;
|
|
echo "Shortest Octet length: {$minOctet}\n";
|
|
echo "Largest Octet length: {$maxOctet}\n";
|
|
}
|
|
|
|
// -i inputFileName
|
|
// -o outputFileName
|
|
// -s minVoxelSize
|
|
// -m method (block|wireframe|surface) assumes surface
|
|
|
|
$options = getopt("i:o:s:m:");
|
|
|
|
global $renderMode;
|
|
//echo "line ".__LINE__." renderMode=$renderMode\n";
|
|
// render options
|
|
switch($options['m']) {
|
|
case 'blocks':
|
|
case 'wireframe':
|
|
case 'surface':
|
|
$renderMode = $options['m'];
|
|
break;
|
|
default:
|
|
$renderMode = 'surface';
|
|
}
|
|
//echo "line ".__LINE__." renderMode=$renderMode\n";
|
|
|
|
// voxelsize
|
|
global $minVoxelSize;
|
|
//echo "line ".__LINE__." minVoxelSize=$minVoxelSize\n";
|
|
if (!empty($options['s'])) {
|
|
if ($options['s'] < 1.0 && $options['s'] > 0.0) {
|
|
$minVoxelSize = $options['s'];
|
|
}
|
|
}
|
|
//echo "line ".__LINE__." minVoxelSize=$minVoxelSize\n";
|
|
|
|
//print_r($options);
|
|
|
|
if (empty($options['i'])) {
|
|
echo "USAGE: objtohio.php -i 'inputFileName' -o 'outputFileName' -m [blocks|wireframe|surface] -s [voxel size] \n";
|
|
}
|
|
else {
|
|
echo "Convering OBJ file input:{$options['i']} output:{$options['o']} mode:$renderMode voxelSize:{$minVoxelSize}\n";
|
|
convertObjFile($options['i'],$options['o']);
|
|
|
|
/*
|
|
$filename = $options['i'];
|
|
$file_handle = fopen($filename, "rt"); // these are text files
|
|
|
|
$line_of_text = fgets($file_handle);
|
|
echo "read: {$line_of_text}";
|
|
|
|
fseek($file_handle,0); // always rewind at the start of each pass
|
|
echo "seek to 0\n";
|
|
|
|
$line_of_text = fgets($file_handle);
|
|
echo "read: {$line_of_text}";
|
|
|
|
fclose($file_handle);
|
|
*/
|
|
}
|
|
?>
|