#!/usr/bin/perl

#
# eps2pov
# v0.1: (c) Ross Martin, 2003 Ross.Martin@ieee.org
#
# This is meant to translate postscript flattened by
# pstoedit into POV input files.
#
# This program may be distributed and used with the 
# POVRay raytracer under POVRay's license conditions
# for distribution and use.  All other rights reserved.
#

$infile=@ARGV[0];

open(INFILE, $infile) || die "Can't open input file $infile";


$_=$infile;
s/.*\///;
/([^.]*)/;
$name=$1;

print "//\n// Translated by eps2pov\n//\n\n";

$sweepstart=0;
$sweepend=1;

while()
{
#
# Skip to beginning of path
#
  while(<INFILE>)
    {
      last if(/.*pathnumber/);
    }

  last if (!$_);

#
# Postscript expects later draws to cover up earlier draws.
# to force this behavior, make later prisms just a shade
# wider so they cover earlier ones up.
#
  $sweepstart -= .000001;
  $sweepend   += .000001;

  /^%[ ]*([^ ]*).*/;
  $path=$1;

  print "//\n// Path $path\n//\n";


  $_=<INFILE>;
    
  if(/.*filledpath/)
    {
      $filledpath=true;
      $strokedpath=false;
    }
  elsif(/.*strokedpath/)
    {
      $filledpath=false;
      $strokedpath=true;
    }
  else
    {
      die "Unknown path type on line $_\n";
    }

#
# Skip startup stuff
#
  $linewidth=1;
  $red=1;
  $green=1;
  $blue=1;

  while(<INFILE>)
    {
      if(/.*setlinewidth/)
        {
          /[ ]*([^ ]*)/;
          $linewidth=$1;
        }
      if(/.*setcmykcolor/)
	{
	  /[ ]*([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)[ ]*([^ ]*)/;
	  ($red,$green,$blue)=cmyk2rgb($1,$2,$3,$4);
	}

      last if(/newpath/);
    }

  $points = 0;

  $p0x[0]=0;
  $p0y[0]=0;
  $firstpointx=0;
  $firstpointy=0;

#
# Process the path
#
  while(<INFILE>)
    {
      if(/.*moveto/)
	{
	  /[ ]*([^ ]*)[ ]*([^ ]*)[ ]*moveto.*$/;
          $p0x[$points]=$1;
          $p0y[$points]=$2;

	  $firstpointx=$1;
	  $firstpointy=$2;
	}
      elsif(/.*curveto/)
	{
          $line=$_;
          s/^[ ]*([^ ]*)[ ]*([^ ]*)//;
          $p1x[$points]=$1;
          $p1y[$points]=$2;
          s/^[ ]*([^ ]*)[ ]*([^ ]*)//;
          $p2x[$points]=$1;
          $p2y[$points]=$2;
          s/^[ ]*([^ ]*)[ ]*([^ ]*)//;
          $p3x[$points]=$1;
          $p3y[$points]=$2;

          $p0x[$points+1]=$p3x[$points];
          $p0y[$points+1]=$p3y[$points];

          $points++;
	}
      elsif(/.*lineto/)
	{
          s/^[ ]*([^ ]*)[ ]*([^ ]*)//;
          $p3x[$points]=$1;
          $p3y[$points]=$2;

          $p1x[$points]=$p0x[$points];
          $p1y[$points]=$p0y[$points];
          $p2x[$points]=$p3x[$points];
          $p2y[$points]=$p3y[$points];

          $p0x[$points+1]=$p3x[$points];
          $p0y[$points+1]=$p3y[$points];

          $points++;
        }
      elsif(/.*closepath/ || /.*fill/)
        {
          if($firstpointx!=$p0x[$points] || $firstpointy!=$p0y[$points])
	    {
              $p3x[$points]=$firstpointx;
              $p3y[$points]=$firstpointy;

	      $p1x[$points]=$p0x[$points];
	      $p1y[$points]=$p0y[$points];
	      $p2x[$points]=$p3x[$points];
	      $p2y[$points]=$p3y[$points];

	      $p0x[$points+1]=$firstpointx;
	      $p0y[$points+1]=$firstpointy;
	      
	      $points++;
	    }

	  if(/.*fill/)
	    {
	      if($points==0)
		{
		  print "#declare ${name}_path_$path = union { }\n";
		  last;
		}
	      
	      $p=4*$points;
	      print "#declare ${name}_path_$path = prism\n{\n linear_sweep bezier_spline\n  $sweepstart, $sweepend,\n  $p";
	      
	      for($i=0; $i<$points; $i++)
		{
		  print ",\n  ";
		  print "<$p0x[$i], $p0y[$i]>, ";
		  print "<$p1x[$i], $p1y[$i]>, ";
              print "<$p2x[$i], $p2y[$i]>, ";
		  print "<$p3x[$i], $p3y[$i]>";
		}
	      
	      print "\n#ifdef(${name}_object_finish)";
	      print "\n  texture { pigment { color rgb <$red,$green,$blue> } finish { ${name}_object_finish } }";
	      print "\n#end";
	      print "\n  sturm\n}\n\n";
	      
	      last;
	    }
	}
      elsif(/.*stroke/)
        {
          if($points==0)
	    {
               print "#declare ${name}_path_$path = union { }\n";
               last;
	    }

          $p=8*($points+1);
          print "#declare ${name}_path_$path = prism\n{\n linear_sweep bezier_spline\n  $sweepstart, $sweepend,\n  $p";
	  
          #
          # Draw left end cap
          #
	  ($p01px,$p01py)=nudgevec($p0x[0],
				   $p0y[0],
				   $p1x[0],
				   $p1y[0],
				   $p2x[0],
				   $p2y[0],
				   $p3x[0],
				   $p3y[0],
				   $linewidth);
	  $s0x = $p0x[0]+$p01px;
	  $s0y = $p0y[0]+$p01py;
	  $s1x = $p1x[0]+$p01px;
	  $s1y = $p1y[0]+$p01py;

	  $r0x = $p0x[0]-$p01px;
	  $r0y = $p0y[0]-$p01py;
	  $r1x = $p1x[0]-$p01px;
	  $r1y = $p1y[0]-$p01py;

	  print ",\n  ";
	  print "<$r0x, $r0y>, ";
	  print "<$s0x, $s0y>, ";
	  print "<$r0x, $r0y>, ";
	  print "<$s0x, $s0y>";

          #
	  # Draw top arc

          for($i=0; $i<$points; $i++)
            {
	      ($p01px,$p01py)=nudgevec($p0x[$i],
				       $p0y[$i],
				       $p1x[$i],
				       $p1y[$i],
				       $p2x[$i],
				       $p2y[$i],
				       $p3x[$i],
				       $p3y[$i],
				       $linewidth);
		
	      if($i>0)
		{
		  ($p01px2,$p01py2)=nudgevec($p3x[$i-1],
					     $p3y[$i-1],
					     $p2x[$i-1],
					     $p2y[$i-1],
					     $p1x[$i-1],
					     $p1y[$i-1],
					     $p0x[$i-1],
					     $p0y[$i-1],
					     -$linewidth);
		  $p01px=0.5*($p01px+$p01px2);
		  $p01py=0.5*($p01py+$p01py2);
		}

	      $s0x = $p0x[$i]+$p01px;
	      $s0y = $p0y[$i]+$p01py;
	      $s1x = $p1x[$i]+$p01px;
	      $s1y = $p1y[$i]+$p01py;

		
	      ($p32px,$p32py)=nudgevec($p3x[$i],
				       $p3y[$i],
				       $p2x[$i],
				       $p2y[$i],
				       $p1x[$i],
				       $p1y[$i],
				       $p0x[$i],
				       $p0y[$i],
				       -$linewidth);

	      if($i<$points-1)
		{
		  ($p32px2,$p32py2)=nudgevec($p0x[$i+1],
					     $p0y[$i+1],
					     $p1x[$i+1],
					     $p1y[$i+1],
					     $p2x[$i+1],
					     $p2y[$i+1],
					     $p3x[$i+1],
					     $p3y[$i+1],
					     $linewidth);
		  $p32px=0.5*($p32px+$p32px2);
		  $p32py=0.5*($p32py+$p32py2);
		}

	      $s2x = $p2x[$i]+$p32px;
	      $s2y = $p2y[$i]+$p32py;
	      $s3x = $p3x[$i]+$p32px;
	      $s3y = $p3y[$i]+$p32py;

              print ",\n  ";
              print "<$s0x, $s0y>, ";
              print "<$s1x, $s1y>, ";
              print "<$s2x, $s2y>, ";
              print "<$s3x, $s3y>";
            }

          #
          # Draw right end cap
          #
	  ($p32px,$p32py)=nudgevec($p3x[$points-1],
				   $p3y[$points-1],
				   $p2x[$points-1],
				   $p2y[$points-1],
				   $p1x[$points-1],
				   $p1y[$points-1],
				   $p0x[$points-1],
				   $p0y[$points-1],
				   -$linewidth);

	  $s3x = $p3x[$points-1]+$p32px;
	  $s3y = $p3y[$points-1]+$p32py;
	  $s2x = $p2x[$points-1]+$p32px;
	  $s2y = $p2y[$points-1]+$p32py;

	  $r3x = $p3x[$points-1]-$p32px;
	  $r3y = $p3y[$points-1]-$p32py;
	  $r2x = $p2x[$points-1]-$p32px;
	  $r2y = $p2y[$points-1]-$p32py;

	  print ",\n  ";
	  print "<$s3x, $s3y>, ";
	  print "<$r3x, $r3y>, ";
	  print "<$s3x, $s3y>, ";
	  print "<$r3x, $r3y>";

          #
	  # Draw bottom arc

          for($i=$points-1; $i>=0; $i--)
            {
	      ($p01px,$p01py)=nudgevec($p0x[$i],
				       $p0y[$i],
				       $p1x[$i],
				       $p1y[$i],
				       $p2x[$i],
				       $p2y[$i],
				       $p3x[$i],
				       $p3y[$i],
				       -$linewidth);
		
	      if($i>0)
		{
		  ($p01px2,$p01py2)=nudgevec($p3x[$i-1],
					     $p3y[$i-1],
					     $p2x[$i-1],
					     $p2y[$i-1],
					     $p1x[$i-1],
					     $p1y[$i-1],
					     $p0x[$i-1],
					     $p0y[$i-1],
					     $linewidth);
		  $p01px=0.5*($p01px+$p01px2);
		  $p01py=0.5*($p01py+$p01py2);
		}

	      $s0x = $p0x[$i]+$p01px;
	      $s0y = $p0y[$i]+$p01py;
	      $s1x = $p1x[$i]+$p01px;
	      $s1y = $p1y[$i]+$p01py;

		
	      ($p32px,$p32py)=nudgevec($p3x[$i],
				       $p3y[$i],
				       $p2x[$i],
				       $p2y[$i],
				       $p1x[$i],
				       $p1y[$i],
				       $p0x[$i],
				       $p0y[$i],
				       $linewidth);

	      if($i<$points-1)
		{
		  ($p32px2,$p32py2)=nudgevec($p0x[$i+1],
					     $p0y[$i+1],
					     $p1x[$i+1],
					     $p1y[$i+1],
					     $p2x[$i+1],
					     $p2y[$i+1],
					     $p3x[$i+1],
					     $p3y[$i+1],
					     -$linewidth);
		  $p32px=0.5*($p32px+$p32px2);
		  $p32py=0.5*($p32py+$p32py2);
		}

	      $s2x = $p2x[$i]+$p32px;
	      $s2y = $p2y[$i]+$p32py;
	      $s3x = $p3x[$i]+$p32px;
	      $s3y = $p3y[$i]+$p32py;

              print ",\n  ";
              print "<$s3x, $s3y>, ";
              print "<$s2x, $s2y>, ";
              print "<$s1x, $s1y>, ";
              print "<$s0x, $s0y>";
            }

          print "\n#ifdef(${name}_object_finish)";
          print "\n  texture { pigment { color rgb <$red,$green,$blue> } finish { ${name}_object_finish } }";
          print "\n#end";
          print "\n  sturm\n}\n\n";

          last;
        }
    }


  last unless $_;
}


print "#declare ${name}_object = union\n";
print "{\n";

for($i=1; $i<=$path; $i++)
  {
    print " object { ${name}_path_$i }\n";
  }

print "}\n";


print "\n//\n// End of data translated by eps2pov\n//\n\n";



sub nudgevec
{
  local($p0x,$p0y,$p1x,$p1y,$p2x,$p2y,$p3x,$p3y,$width)=@_;

  local($p01px)=$p1y-$p0y;
  local($p01py)=$p0x-$p1x;
  local($p01mag)=sqrt($p01px*$p01px+$p01py*$p01py);
  if($p01mag==0)
    {
      $p01px=$p2y-$p0y;
      $p01py=$p0x-$p2x;
      $p01mag=sqrt($p01px*$p01px+$p01py*$p01py);

      if($p01mag==0)
        {
          $p01px=$p3y-$p0y;
          $p01py=$p0x-$p3x;
          $p01mag=sqrt($p01px*$p01px+$p01py*$p01py);
        }
    }

  local($p01norm)=0.0;
  if($p01mag!=0)
    {
      $p01norm=0.5*$width/$p01mag;
    }

  $p01px*=$p01norm;
  $p01py*=$p01norm;

  local(@returnval)=($p01px,$p01py);
}


#
# From the newgroups...
#
# The simple CMY color model conversion is like this:
#
#    [ C ]   [ 1 ]   [ R ]     [ R ]   [ 1 ]   [ C ]
#    | M | = | 1 | - | G |  ;  | G | = | 1 | - | M |
#    [ Y ]   [ 1 ]   [ B ]     [ B ]   [ 1 ]   [ Y ]
#
# CMY (cyan, magenta, and yellow) is just the complement to RGB (red, green,
# blue).  Now the CMYK color model add a fourth plate for pure black.  This
# is the conversion (from CMY to CMYK)
#
#    K = min(C , M , Y ),
#             0   0   0
#    C = C  - K,
#         0
#    M = M  - K,
#         0
#    Y = Y  - K.
#         0
#
# Hope this helps.
#
# P.S. My source for this was...
#
#    Foley, J., A. van Dam, S. Feiner, J. Hughes, and R. Phillips,
#        _Introduction_to_Computer_Graphics_, Addision-Wesley,
#        Reading, Mass., 1994.
#



sub cmyk2rgb
{
  local($c,$m,$y,$k)=@_;

  local($r)=1-$c-$k;
  local($g)=1-$m-$k;
  local($b)=1-$y-$k;

  $r=0 if($r<0);
  $g=0 if($g<0);
  $b=0 if($b<0);

  ($r,$g,$b);
}
