#!/usr/local/bin/perl -w
#
# Create the RIB for "And Now For a Word"
# 

use RIB;
use POSIX;

#
# Constants and configuration
$PI = 2 * acos (0);  # the constant Pi
$hillangle = 10;     # right-to-left angle of the hillside to the camera
$leftx = -1.4;       # leftmost letter x coord
$lefty = -0.5;       # leftmost letter y coord
$leftz =  0.5;       # leftmost letter z coord
$lsp   =  0.08;      # spacing between letters
$rscl  =  0.014;     # how much too big the rack models are

#
# Letter data--name, and bounding box (for decal shader)
@hdata = ( 'h', -0.193,  0.193,  -0.342, 0.342 );
@odata = ( 'o', -0.1965, 0.1965, -0.342, 0.342 );
@ldata = ( 'l', -0.1515, 0.1515, -0.342, 0.342 );
@ydata = ( 'y', -0.2195, 0.2195, -0.342, 0.342 );
@wdata = ( 'w', -0.2293, 0.2293, -0.342, 0.342 );
@ddata = ( 'd', -0.197,  0.197,  -0.342, 0.342 );

$width = $ARGV [0] if (defined ($ARGV [0]));
$width = 320 unless (defined ($width));

$height = $ARGV [1] if (defined ($ARGV [1]));
$height = 240 unless (defined ($height));

$samples = $ARGV [2] if (defined ($ARGV [1]));
$samples = 1 unless (defined ($samples));

#
# General scene-related things
RiBegin("cr-nword.rib");
RiOption ('searchpath', shader => 'shaders:&');
RiOption ('runtime', verbosity => 'stats');
RiFormat ($width, $height, 1);
RiPixelSamples ($samples, $samples);

#
# Declare shader variables
# For decal shader
RiDeclare (plane          => 'float');
RiDeclare (c0min          => 'float');
RiDeclare (c0max          => 'float');
RiDeclare (c1min          => 'float');
RiDeclare (c1max          => 'float');
# For STDisplace displacement mapper
RiDeclare (Km             => 'float');
RiDeclare (_STMapping     => 'float');
# For sky and ground (CRBlueSky) texture
RiDeclare (txtscale       => 'uniform float');
RiDeclare (skycolor       => 'color');
RiDeclare (cloudcolor     => 'color');
RiDeclare (omega          => 'float');
# For all lightsource shaders
RiDeclare (shadows        => 'string');

#
# Lighting
# Backwards shadowless light cuz the letters poly facing is backwards
RiLightSource (RI_DISTANTLIGHT, intensity => 10,
               from => [ 0, 0, 0 ], to => [ sin (&dr ($hillangle * 2)), 0, -1 ]);
# Ground bounce
RiLightSource (RI_POINTLIGHT, intensity => 5,
               from => [ 1, -1, 1 ], lightcolor => [ 0.25, 0.25, 0 ]);
# Sky fill
RiLightSource (RI_DISTANTLIGHT, intensity => 20,
               from => [ 0, 0, 0 ], to => [ 0, -1, -0.1 ],
               lightcolor => [ 0.72, 0.72, 0.83 ]);
# Main scene light--simulate the sun
RiAttribute ('light', shadows => 'on');
RiLightSource (RI_DISTANTLIGHT, intensity => 100,
               from => [ 0, 0, 0 ], to => [ -1, -1, 1],
               lightcolor => [ 1, 0.99, 0.95 ]);  # smoggy sunlight <g>

#
# Set scene parameters
RiProjection (RI_PERSPECTIVE);

#
# Draw the scene
RiFrameBegin (0);
RiDisplay ("cr-nword-t.tif", "file", "rgba");
RiTranslate (0, 0, 2);
&world ();
RiFrameEnd ();
RiEnd();
exit (0);


#
# Draw one frame of the world (in this case, the only one)
sub world
{
   RiWorldBegin ();
   RiTranslate (-0.5, 0, -0.7);
   RiColor (1, 1, 1);

#
# The sky
   RiAttributeBegin ();
   RiSurface ('KMPuffyClouds', txtscale => 0.05,
              skycolor   => [ .45, .45, .6 ],
              omega => 0.45);
   RiPatch (RI_BILINEAR, RI_P, [ -100, 3.0,   0,  100, 3.0,   0,
                                 -100, 2.9, 100,  100, 2.9, 100 ]);
   RiAttributeEnd ();

#
# The hillside
   RiAttributeBegin ();
   RiTranslate (-0.5, -1.3, -0.3);
   RiAttribute ('render', truedisplacement => 1);
   RiAttribute ('displacementbound', coordinatesystem => 'object', sphere => 10);
   RiRotate ($hillangle, 0, 1, 0);
   RiRotate (-55, 1, 0, 0);
   RiSurface ('CRBlueSky', txtscale => 0.05, Kd => 40,
              cloudcolor => [ 0.070, 0.175, 0.080 ],
              skycolor   => [ 0.376, 0.282, 0.000 ],
              omega => 0.85);

   RiDisplacement ('STDisplace', texturename => 'maps/hillside.tiff',
                   Km => 1, _STMapping => 0);
   RiPatch (RI_BILINEAR, RI_P, [ -4, 0, -2,  4, 0, -2,  -4, 0, 2,  4, 0, 2 ]);
   RiAttributeEnd ();

#
# The letters
   RiAttributeBegin ();
   $xpos = $leftx;
   $letterangle = $hillangle;  # we artificially rotate the letters
   &draw_character (@hdata, $xpos, $lefty + 0.000, 'h');
   &draw_character (@odata, $xpos, $lefty + 0.030, 'o1');
   &draw_character (@ldata, $xpos, $lefty - 0.010, 'l1');
   &draw_character (@ldata, $xpos, $lefty - 0.016, 'l2');
   &draw_character (@ydata, $xpos, $lefty - 0.035, 'y');
   &draw_character (@wdata, $xpos, $lefty - 0.030, 'w');
   &draw_character (@odata, $xpos, $lefty + 0.050, 'o2');
   &draw_character (@odata, $xpos, $lefty + 0.130, 'o3');
   &draw_character (@ddata, $xpos, $lefty + 0.130, 'd');
   RiAttributeEnd ();

   RiWorldEnd ();
}


#
# Draw a character given its data array, x and y positions, and texture map name
sub draw_character
{
   my ($cname, $c0min, $c0max, $c1min, $c1max, $x, $y, $mname) = @_;

   RiAttributeBegin ();
   # The Z calculation makes the letters follow the hillside
   RiTranslate ($x, $y, $leftz  - (($x - $leftx) * sin (&dr ($hillangle))));
   RiRotate ($letterangle, 0, 1, 0);
   if ($cname ne 'l')  # the "L" racks don't show, so eliminate them
   {
      &draw_rack (0.05);
   }
   RiSurface ('CRDecal', texturename => "maps/$mname-map.tiff", plane => 0,
              Kd => 0.1,
              c0min => $c0min, c0max => $c0max, c1min => $c1min, c1max => $c1max);
   if ($cname eq 'w')  # our "W" is twice too wide
   {
      RiScale (0.5, 1.0, 1.0);
   }
   RiReadArchive ("rib/$cname.inc");
   RiAttributeEnd ();
   $xpos += ($c0max - $c0min) + $lsp;  # advance "cursor"
   $letterangle += 2;
}


#
# Draw the rack a letter is mounted on
sub draw_rack
{
   my ($down) = shift;

   RiAttributeBegin ();
   RiScale ($rscl, $rscl, $rscl);
   RiTranslate (0, -$down, 0);
   RiDisplacement ('LGDented', Km => 0.01);
   RiColor (0.5, 0.5, 0.5);
   RiSurface ('plastic', Ks => 0.001, Kd => 0.05);
   RiReadArchive ('rib/rack.inc');
   RiAttributeEnd ();
}


#
# Degrees to radians
sub dr
{
   my ($deg) = shift;

   return ($deg * $PI) / 180;
}
