/* Renamed shader to PQCrayon for RMR -- tal AT renderman DOT org */

/* crayon.sl - a surface shader making crayon like marks

	DESCRIPTION

	This shader makes the surface look as if it had been shaded with a pastel crayon.
	It makes an attempt at antaliasing.
	
	PARAMETERS
	
	Ka, Kd, Ks, roughness, specularcolor - work as in the plastic shader
	txtscale  - an overall scaling factor
	width - the width of the crayon strokes - this is scaled by txtscale
	micro - the size of the dots that make up a crayon stroke, relative to the size of
		the stroke. By default they are about 15 times smaller
	stretch - the length of the stroke relative to its width;
	density0 - controls the amount of topcolor seen - measured as a proportion - 
		this should vary between 0 (no topcolor) to 1, .3 would give 30% topcolor;
	density1 - if different density0 this is the density when t = 1, with a smooth
		interpolation of values for density0 when t = 0, thus allowing a 
		graduation of shading from top to bottom of the object
	color topcolor, basecolor - the color of the crayon strokes and the color of the ground
	
	AUTHOR
	Peter Quint - Revised Monday, January 10, 2000 

 */
 
 

#define snoise(x,y) ((noise(x,y) - 0.5) * 2)

float
aanoise(float sp, tp, width)
{
	/* an antaliased noise function, which returns noise of a wavelenth always greater than
	   twice the micropolygon width */
	float f, mag, ns;
	/* calculate smallest integer f for which width / f < .5 */
	f = ceil(width /.5);
	mag = max(pow(0.85, f - 1),.1);
	/*(printf("f = %f, mag = %f\n",f,mag)*/;
	ns  = mag * snoise(sp / f, tp / f) * (1 - smoothstep(0, .5, width / f))
		+ snoise(sp / (f * 1.33), tp / (f * 1.33)) * mag * .25 * smoothstep(0, .5, width / f);
	return ns;
}


#define MINFILTWIDTH 1.0e-6
#define filterwidth(x)  max (abs(Du(x)*du) + abs(Dv(x)*dv), MINFILTWIDTH)


surface
PQCrayon (	float Ka = 1;
        	float Kd = .5;
         	float Ks = .5;
         	float roughness = .1;
	 		color specularcolor = 1;
			float txtscale = 1;
			float width = .05;
			float micro = 15.32;
			float stretch = 10;
			float density0 = .5;
			float density1 = .5;
			color topcolor = 1;
			color basecolor = 0;
		)
{
  color Csurf;
    float density = density0 + t * (density1 - density0);
	/* work out the density for the current t */
	float trs = spline(1 - density, 0 , -0.195997, -0.128361, -0.0738346,	-0.0316483,
			0.00807387,	0.0445915, 0.084543, 0.150693, 0.2198, 0.527474);
	/*  use a spline to read across to the appropriate noise value - this equalisation
		process is described by Steven Worley in Ch 3 of "Texturing and Modelling a
		procedural approach */ 
	normal Nf = faceforward (normalize(N),I);
	float m;
	float fw = max(filterwidth(s), filterwidth(t)); /* the size of the micropolygon */
	float smks = aanoise(txtscale * s * micro / width, txtscale * t * micro / width,
	 		txtscale * fw * micro / width);
	float lmks = (aanoise(txtscale * s / width, txtscale * t / (width * stretch), 
		txtscale * fw / width) + 1) / 2;
	smks = (smks + 1) / 2;
	lmks = lmks - smks;
	m = smoothstep(trs - .1, trs + .3, lmks);	
	m = clamp(m, 0, 1);
	Csurf = mix(basecolor, topcolor, m);
	Oi = Os;
    Ci = Os * ( Csurf * (Ka*ambient() + Kd*diffuse(Nf)) +
		specularcolor * Ks*specular(Nf,-normalize(I),roughness));
}



