/* I took wave's lead and renamed starfield to KMCyclone.sl -- tal AT renderman DOT org */

/*
 * cyclone.sl - surface for a semi-opaque cloud layer to be put on an
 *              earth-like planetary model to model clouds and a cyclone.
 *
 * DESCRIPTION:
 *      When put on a sphere, sets the color & opacity of the sphere to
 *   make it look like the clouds surrounding an Earth-like planet, with
 *   a big cyclone.
 *      The shader works by creating a fractal turbulence function over
 *   the surface, then modulating the opacity based on this function in
 *   a way that looks like clouds on a planetary scale.
 *
 *
 * PARAMETERS:
 *    Ka, Kd - the usual meaning
 *    cloudcolor - the color of the clouds, usually white
 *    max_radius
 *    twist - controls the twisting of the clouds due to the cyclone.
 *    offset, scale - control the linear scaling of the cloud value.
 *    omega, octaves - controls the fractal characteristics of the clouds
 *
 *
 * HINTS:
 *    See the "planetclouds" shader for hints which apply equally well
 *    to this shader.
 *
 *
 * AUTHOR: Ken Musgrave
 *    Conversion to Shading Language and other minor changes by Larry Gritz.
 *
 * REFERENCES:
 *    _Texturing and Modeling: A Procedural Approach_, by David S. Ebert, ed.,
 *    F. Kenton Musgrave, Darwyn Peachey, Ken Perlin, and Steven Worley.
 *    Academic Press, 1994.  ISBN 0-12-228760-6.
 *
 * HISTORY:
 *    ???? - original texture developed by Ken Musgrave.
 *    Feb 1994 - Conversion to Shading Language by L. Gritz
 *
 * last modified 1 March 1994 by lg
 */



#define TWOPI (2*PI)

/* Use signed Perlin noise */
#define snoise(x) ((2*noise(x))-1)
#define DNoise(p) (2*(point noise(p)) - point(1,1,1))
#define VLNoise(Pt,scale) (snoise(DNoise(Pt)+(scale*Pt)))
#define VERY_SMALL 0.001




surface
KMCyclone (float Ka = 0.5, Kd = 0.75;
	 float max_radius = 1;
	 float twist = 0.5;
	 float scale = .7, offset = .5;
	 float omega = 0.675;
	 float octaves = 4;)
{
  float radius, dist, angle, sine, cosine, eye_weight, value;
  point Pt;                 /* Point in texture space */
  point PN;                 /* Normalized vector in texture space */
  point PP;                 /* Point after distortion */
  float l, o, a, i;         /* Loop control for fractal sum */

  /* Transform to texture coordinates */
  Pt = transform ("shader", P);

  /* Rotate hit point to "cyclone space" */
  PN = normalize (Pt);
  radius = sqrt (xcomp(PN)*xcomp(PN) + ycomp(PN)*ycomp(PN));

  if (radius < max_radius) {   /* inside of cyclone */
      /* invert distance from center */
      dist = pow (max_radius - radius, 3);
      angle = PI + twist * TWOPI * (max_radius-dist) / max_radius;
      sine = sin (angle);
      cosine = cos (angle);
      PP = point (xcomp(Pt)*cosine - ycomp(Pt)*sine,
		  xcomp(Pt)*sine + ycomp(Pt)*cosine,
		  zcomp(Pt));
      /* Subtract out "eye" of storm */
      if (radius < 0.05*max_radius) {  /* if in "eye" */
	  eye_weight = (.1*max_radius - radius) * 10;   /* normalize */
	  /* invert and make nonlinear */
	  eye_weight = pow (1 - eye_weight, 4);
	}
      else eye_weight = 1;
    }
  else PP = Pt;

  if (eye_weight > 0) {   /* if in "storm" area */
      /* Compute VLfBm */
      l = 1;  o = 1;  a = 0;
      for (i = 0;  i < octaves  &&  o >= VERY_SMALL;  i += 1) {
	  a += o * VLNoise (PP * l, 1);
	  l *= 2;
	  o *= omega;
	}
      value = abs (eye_weight * (offset + scale * a));
    }
  else value = 0;

  /* Thin the density of the clouds */
  Oi = value * Os;

  /* Shade like matte, but with color scaled by cloud opacity */
  Ci = Oi * (Ka * ambient() + Kd * diffuse(faceforward(normalize(N),I)));
}
