/*
 * WWCinderBlock.sl -- a surface shader for cinder block walls.
 *
 * DESCRIPTION:
 *   This is a surface shader which combines a matte shader and 
  *  Larry Gritz's brick displacement shader.  
 *   Makes displacements for a wall of bricks.  This is the companion
 *   shader to the surface "brick" shader.  The parameters work exactly
 *   the same.  Of course, you can use it with any surface shader, and
 *   in fact matte or plastic gives those nice white cinder block walls.
 *   However, if you do use it with "brick", the parameters MUST match,
 *   or your bricks will look very strange.
 * 
 * PARAMETERS:
 *    brickwidth                Width of a brick (in st space)
 *    brickheight               Height of a brick (in st space)
 *    mortarthickness           Thickness of the mortar (in st space)
 *    rowvary                   How much does each row shift?
 *    jagged                    How much do bricks deviate from squares?
 *    pitting                   The amplitude of the "pits" on the face of
 *                                 the bricks.
 *    pockfrequency             The st frequency of the pits.
 *    groovedepth               The depth of the grooves between bricks.
 *
 * AUTHOR: written by Larry Gritz, 1992, transmuted by wave in 1994
 *
 * HISTORY:
 *      28 May 1992 -- written by lg for the "Timbre Trees" video (saucer)
 *      12 Jan 1994 -- recoded by lg in correct shading language.
 *      8  Dec 1994 -- hacked unmercifully by wave
 *      10 Jan 1995 -- changed defaults
 *
 * last modified  10 Jan 1995 by wave
 */

surface
WWCinderBlock (float Ka	= .7; 
	       float Kd	= .7;
               float jagged = 0.006;
   	       color brickcolor = color "rgb" (1, 1, .82);
	       color mortarcolor = color "rgb" (1, 1, .82);
               float brickwidth = .3, brickheight = .15;
	       float mortarthickness = .01; 
               float brickvary = 0.15;
	       float rowvary = .01, pitting = 0.03;
	       float pockfrequency = 15, groovedepth = 0.025; )
{
#define BMWIDTH (brickwidth+mortarthickness)
#define BMHEIGHT (brickheight+mortarthickness)
#define MWF (mortarthickness*0.5/BMWIDTH)
#define MHF (mortarthickness*0.5/BMHEIGHT)
#define snoise(x) (2 * noise((x)) - 1)
#define boxstep(a,b,x) (clamp(((x)-(a))/((b)-(a)),0,1))
#define sqr(x) ((x)*(x))
#define MINFILTERWIDTH 1.0e-7
  point PP2, tmpP;
  float sbrick, tbrick, w, h;
  float scoord, tcoord, ss, tt;
  float fact, disp;
  point Nf;
  float swidth, twidth;
  color bcolor, Ct;

  /* Determine how wide in s-t space one pixel projects to */
  swidth = max (abs(Du(s)*du) + abs(Dv(s)*dv), MINFILTERWIDTH);
  twidth = max (abs(Du(t)*du) + abs(Dv(t)*dv), MINFILTERWIDTH);

  scoord = s;  tcoord = t;

  /* Make the shapes of the bricks vary just a bit */
  PP2 = point noise (s/BMWIDTH, t/BMHEIGHT);
  scoord = s + jagged * xcomp (PP2);
  tcoord = t + jagged * ycomp (PP2);

  ss = scoord / BMWIDTH;
  tt = tcoord / BMHEIGHT;

  /* shift alternate rows */
  if (mod (tt*0.5, 1) > 0.5)
      ss += 0.5;

  tbrick = floor (tt);   /* which brick row? */
  /* Shift the columns randomly by row */
  ss += rowvary * (noise (tbrick+0.5) - 0.5);

  sbrick = floor (ss);   /* which brick column? */
  ss -= sbrick;          /* Now ss and tt are coords within the brick */
  tt -= tbrick;

  fact = 1;
  disp = 0;
  if (tt < MHF) {
      /* We're in the top horizontal groove */
      disp = groovedepth * (sqr((tt)/MHF) - 1);
    }
  if (tt > (1.0-MHF)) {
      /* Bottom horizontal groove */
      disp = groovedepth * (sqr((1-tt)/MHF) - 1);
    }
  if (ss < MWF) {
      disp = 0.75 * groovedepth * (sqr(ss/MWF) - 1);
    }
  if (ss > (1.0-MWF)) {
      disp = 0.75 * groovedepth * (sqr((1-ss)/MWF) - 1);
    }

  fact = smoothstep (0, 1.3*MHF, tt) - smoothstep (1.0-1.3*MHF, 1, tt);
  fact *= (smoothstep (0, 1.3*MWF, ss) - smoothstep (1.0-1.3*MWF, 1, ss));
  fact = pitting * (0.75 * fact + 0.25);
  disp -= fact * pow(noise ((ss+sbrick)*pockfrequency/BMHEIGHT,
		            (tt+tbrick)*pockfrequency/BMWIDTH), 0.25);

  tmpP = P + (disp * normalize(N));
  /* okay, we perturb the normal, but not the real point, so we can't see through the wall... */
  N = calculatenormal(tmpP);
  Nf = faceforward(normalize(N),I);

  /* Choose a color for the surface */
  if (swidth >= 1)
      w = 1 - 2*MWF;
  else w = clamp (boxstep(MWF-swidth,MWF,ss), max(1-MWF/swidth,0), 1)
	 - clamp (boxstep(1-MWF-swidth,1-MWF,ss), 0, 2*MWF/swidth);

  if (twidth >= 1)
      h = 1 - 2*MHF;
  else h = clamp (boxstep(MHF-twidth,MHF,tt), max(1-MHF/twidth,0),1)
	 - clamp (boxstep(1-MHF-twidth,1-MHF,tt), 0, 2*MHF/twidth);

  /* Choose a brick color that varies from brick to brick */
  /*
  bcolor = brickcolor * (1 + (brickvary * snoise (tbrick+(100*sbrick)+0.5)));
  */
  bcolor = brickcolor * (1 + (brickvary * snoise (tbrick+0.5)));
  Ct = mix (mortarcolor, bcolor, w*h);


  Oi = 1;
  Ci = Ct * ( Ka*ambient() + Kd*diffuse(Nf) ) ;
}
