/*
 * Renamed to JMredapple.sl for RMR -- tal AT renderman DOT org  7/18/99
 *
 * redapple.sl - A nice shader for reddy-green apples.
 *
 * Copyright (C) Jonathan Merritt, 1999.
 * Feel free to use this shader to create apples anywhere and
 * everywhere.
 *
 * This shader creates a nice skin for red-green apples. It _is_ tuned
 * for specific geometry, but can very easily be adjusted to fit any
 * apple you care to lay it on. Apples are requred to have the "s"
 * texture parameter running equatorialy around them (like latitude
 * lines), and "t" running from pole to pole (like longditude). Apples
 * look best from the side, but work ok from the top, so long as you
 * don't mind the simple lerping I used to fade to green at the poles.
 *
 * Look out for the "txtscale" parameter: some noise calculations are
 * done using shader space, instead of "s" and "t" parameters (I think
 * my apple's parameters are stretched a bit?), so if you use
 * different size apples, make sure to change txtscale appropriately.
 *
 * I think this shader is really cool. If you think so too, you can
 * email me your praises, notification of my credits in big motion
 * pictures, job offers at Pixar, etc... to:  jmerritt AT warpax DOT com    :-)
 *
 * Have FUN!!!   :-)
 */


/*#define USE_LG_RAYTRACE */

#ifdef USE_LG_RAYTRACE
#include "rayserver.h"
#include "raytrace.h"
#endif

#ifndef snoise
#define snoise(x) (2*noise(x)-1)  /* 1-D signed noise */
#endif

#define TSCALE .05

surface
JMredapple (
	float Ks = .25;           /* Specular reflection coeff.    */
	float Kd = .5;            /* Diffuse reflection coeff.     */
	float Ka = 1;             /* Ambient light coeff.          */
	float Kr = .05;           /* Mirror-like reflection coeff. */
	float roughness = .1;     /* Specular roughness param.     */
	float label = 0;          /* Non-uniformity param.         */
	float redness = 1;        /* Amount of 'redness' - higher  */
	                          /*  values give redder apples.   */
	                          /*  2 = almost complete red.     */
	float txtscale = .05;     /* Ugly kludge (see above...)    */
	color specularcolor = 1;  /* Specular reflection color     */
)
{
	/*
	 * Shader variables
	 */
	vector Nf, V, Rdir;
	point PP, newP;
	float base_turb, blotch_turb, disp_turb;
	float small_noise, blotch, speck, disp = 0, blackness;
	color cs, small_speckle, base_color, reflect;


	/*
	 * Some nice colors for our red apple
	 */
	color red   = color(0.52,0.00,0.00);
	color dred  = color(0.40,0.00,0.00);
	color green = color(0.76,0.80,0.37);
	color brown = color(0.70,0.78,0.34);
	color black = color(0.00,0.00,0.00);


	/*
	 * Standard settings
	 */
	PP = transform("shader", P);
	V = normalize(-I);


	/*
	 * Pick the base color for the apple.
	 *
	 * The base color consists of patches of pure green,
	 * and patches of finely speckled red and green. These
	 * are set up so that the poles of the apple (as "t"
	 * goes to 1 or 0) are colored more and more green.
	 *
	 * The apple geometry is such that lines of constant
	 * "t" are lines of longditude (from pole to pole).
	 * The constants T1 - T4 specify locations of the
	 * start of 'greenness' toward the poles.
	 */
	#define BASE_SF          1.2    /* s-factor for big noise          */
	#define BASE_TF          3      /* t-factor for big noise          */
	#define BASE_NF          100    /* scaling factor for small noise  */
	#define BASE_NOISE_AMP   0.2    /* small noise color mix amplitude */
	#define BASE_GRC         0.4    /* shift factor for more red       */
	#define T1               0.0    /* t < T1 is pure green            */
	#define T2               0.18   /* lerp s.t. T1->T2 => green->red  */
	#define T3               0.8    /* T2->T3 => red can exist here    */
	#define T4               1.0    /* lerp s.t. T3->T4 => red->green  */
	                                /* t > T4 is pure green            */
	base_turb = noise(BASE_SF*sin(2*PI*s) + PI + label,
	                  BASE_TF*t + label);
	base_turb = pow(base_turb, (1/redness));
	small_noise = snoise(BASE_NF*PP*txtscale/TSCALE);
	small_speckle = mix(red, green, BASE_GRC+
	                    (small_noise*BASE_NOISE_AMP));
	if (t < T1)
		base_turb = 0;
	else if (t >= T1 && t < T2)
		base_turb *= (t-T1)/(T2-T1);
	else if (t >= T3 && t < T4)
		base_turb *= (T4-t)/(T4-T3);
	else if (t >= T4)
		base_turb = 0;
	base_color = spline(base_turb, green, green,
	                    small_speckle, small_speckle,
	                    small_speckle);


	/*
	 * Pick the blotch color.
	 *
	 * The blotch color is finally determined by mixing,
	 * using the blotching coefficient "blotch". This
	 * section sets that coefficient, using a funky yet
	 * really simple noise routine.
	 */
	#define BLOTCH_SF          20   /* s-factor for blotches  */
	#define BLOTCH_TF          15   /* t-factor for blotches  */
	#define BLOTCH_TCF         2.5  /* scaling kludge         */
	#define BLOTCH_DELTA       0.1  /* 'nother scaling kludge */
	#define BLOTCH_SPECK_COEFF 0.3  /* blotch specking coeff  */
	blotch_turb = noise(BLOTCH_SF*sin(2*PI*(s+.1234)) + PI + label,
	                    BLOTCH_TF*t + label) + BLOTCH_DELTA;
	blotch = pow(blotch_turb, 1.3) * BLOTCH_TCF * 
	         pow(base_turb, 2);
	blotch = blotch * (1+small_noise) +
	         small_noise * BLOTCH_SPECK_COEFF;
	if (blotch > 1) blotch = 1;


	/*
	 * Set the brown specking.
	 *
	 * The apple has brown speckles on it, set by mixing
	 * using the speckling coefficient "speck". These
	 * specks are very dot-like in nature, and this
	 * dottiness technique is stolen from LG's starfield 
	 * shader.
	 */
	#define SPECK_NF        50    /* A noise scaling factor      */
	#define SPECK_CUTOFF    .45   /* Cutoff for 'tops' of specks */
	speck = pow(smoothstep(SPECK_CUTOFF, 1,
	            noise(SPECK_NF*PP*txtscale/TSCALE)), 3);

	/*
	 * Determine where the apple goes black at the poles.
	 * This simulates the spots where the stalk would be
	 * attached, and where the wierd bit at the very bottom
	 * is.
	 */
	#define BEDGE  .01
	#define BWIDTH .01
	blackness = 1-(smoothstep(BEDGE, BEDGE+BWIDTH, t)*
	               smoothstep(BEDGE, BEDGE+BWIDTH, 1-t));


	/*
	 * Combine what we have so far to set the surface
	 * color.
	 */
	cs = mix(base_color, dred, blotch);
	cs = mix(cs, brown, speck);
	cs = mix(cs, black, blackness);


	/*
	 * Set the shading surface normal.
	 *
	 * Here we set the surface normal to fix up the specular
	 * highlights. We'd like them perturbed by the small
	 * noise, affected a little by the brown specks, and
	 * also dented a bit (alas, no real apples are perfectly
	 * un-dented).
	 */
	#define DISP_SF     10             /* s-factor for dent noise */
	#define DISP_TF     30             /* t-factor for dent noise */
	#define DISP_DENT_AMP     (1/15)   /* dent amplitude          */
	#define DISP_SMNOISE_AMP  (1/1000) /* small noise amplitude   */
	#define DISP_SPECK_AMP    (1/40)   /* speckle disp. amplitude */
	disp += noise(DISP_SF*sin(2*PI*s) + PI + label,
	              DISP_TF*t + label) * DISP_DENT_AMP * txtscale / TSCALE;
	disp += small_noise * DISP_SMNOISE_AMP * txtscale / TSCALE;
	disp -= speck * DISP_SPECK_AMP * txtscale / TSCALE;
	newP = calculatenormal(P + disp * normalize(N));
	Nf = faceforward(normalize(newP), I);


	/*
	 * 'Mirror' reflections
	 *
	 * Here, we raytrace for the slight mirrored reflections
	 * in the surface of an apple. They don't add much, but
	 * may be needed for the 'perfect' apple :-).
	 *
	 * Note: You'll need Larry Gritz's raytrace helper files
	 * for this bit!
	 */
#ifdef USE_LG_RAYTRACE
	if (Kr > .01) {
		Rdir = normalize(reflect(normalize(I), Nf));
		reflect = RayTrace(P, Rdir, 0, 1, 1);
	} else {
		reflect = 0;
	}
#else
	reflect = 0;
#endif


	/*
	 * Combine everything to get Ci, in the standard form.
	 */
	Oi = Os;
	Ci = Os * (cs * (Ka*ambient() + Kd*diffuse(Nf)) +
	           specularcolor * (Kr * reflect +
	                            Ks * specular(Nf, V, roughness)));
		
}



