/*
 * Barnacle support functions
 * Peter Stuart
 * $Id: barnacle.h,v 1.2 2003/11/12 22:01:31 ophi Exp $
 * description: Support functions that build the color and
 *   displacement for a single barnacle
*/

#ifndef __BARNACLE_H__
#define __BARNACLE_H__

#include "sl2vex.h"
#include "rn.h"
#include "shapes.h"
#include "xforms.h"

/* ---- functions to create random transformation and inverse -----
 * scale_min, scale_max: range of scaling
 * rot_min, rot_max: range of rotation
 * seed: controls transformation
 * row, col: row and column of current tile
 * s, t: current position
 * ss, tt: returned position
 *
 * the rand_xform_params provides a way of making sure both the forward and
 * inverse transforms use the same parameters.
 *
 * FIXME pebbles.sl uses the exact same functions - move to a header file...
 */
void rand_xform_params(float scale_min, scale_max;
		       float rot_min, rot_max;
		       float seed;
		       float row, col;
		       output float sx, sy, tx, ty, rot)
{
  float scale1 = udn2(col+RN(1), row+RN(2), scale_min, scale_max) / 2;
  float scale2 = udn2(col+RN(3), row+RN(4), scale_min, scale_max) / 2;
  sx = 2*scale1;
  sy = 2*scale2;
  tx = udn2(col+RN(5), row+RN(6), scale1-0.5, 0.5-scale1) / 2;
  ty = udn2(col+RN(7), row+RN(8), scale2-0.5, 0.5-scale2) / 2;
  rot = udn2(col+RN(9), row+RN(10), rot_min, rot_max);
}

void rand_xform(float scale_min, scale_max;
		float rot_min, rot_max;
		float seed;
		float row, col, s, t;
		output float ss, tt;)
{
  float sx, sy, tx, ty, rot;
  rand_xform_params(scale_min, scale_max,
		    rot_min, rot_max, seed, row, col,
		    sx, sy, tx, ty, rot);
  xform_rot(sx, sy, tx, ty, rot, s, t, ss, tt);
}

void rand_xform_inv(float scale_min, scale_max;
		    float rot_min, rot_max;
		    float seed;
		    float row, col, s, t;
		    output float ss, tt;)
{
  float sx, sy, tx, ty, rot;
  rand_xform_params(scale_min, scale_max,
		    rot_min, rot_max, seed, row, col,
		    sx, sy, tx, ty, rot);
  xform_rot_inv(sx, sy, tx, ty, rot, s, t, ss, tt);
}

/* ---- barnacle_radii --------
 * ncones: number of bulges in cone
 * minrad, maxrad: minimum and maximum radii of cone
 * _seed: controls random attributes
 * s, t: texture coordinates
 * botrad, toprad: returned value for top and bottom of cone
 * r, theta: returned polar coordinates of s, t
 * thfactor: returned factor for theta (ncones / 2 PI)
 *
 * support function to share implementation between color and
 * displacement
 */
void barnacle_radii(uniform float ncones;
		    float minrad, maxrad;
		    float _seed;
		    float s, t;
		    output float botrad, toprad;
		    output float r, theta, thfactor;)
{
  float seed = floor(_seed);
  topolar2d(s, t, r, theta);
  thfactor = ncones / (2*PI);

  /* line up noise along theta to avoid breaks (assuming seed is integer) */
  /* FIXME this doesn't really avoid breaks! */
  botrad = maxrad + maxrad*abs(snoise(theta*thfactor + RN(98) - RN_OFFS));
  toprad = minrad + minrad*abs(snoise(theta*thfactor + RN(100) - RN_OFFS));
}


/***** common transformation and testing *************************
 * s, t: texture coordinates in global space
 * sfreq, tfreq: number of barnacles in s and t
 * col, row: column and row of current barnacle
 * bomb: the identifier assigned to this tile
 * sparse, variation: controls distribution of barnacles
 * seed: controls random attributes
 * xs, xt: the s,t coordinates transformed into barnacle space
 *
 * return the 1 if the barnacle should be drawn, 0 otherwise
 */
float test_and_xform(float s, t, sfreq, tfreq, col, row;
		     float bomb, sparse, variation, seed;
		     output float xs, xt;)
{
  float retval = 0;
  float ss = s + udn(bomb+RN(2981), -1.5, 1.5);
  float tt = t + udn(bomb+RN(651511), -1.5, 1.5);
      
  /* barnacle density */
  float density = 1 - sparse * 
    smoothstep(0.25, 0.75, float(noise(col*variation/sfreq,
				       row*variation/tfreq)));
  if (noise(bomb+RN(2989101)) <=
      blend(blend(1,density,2*sparse),
	    blend(density, 0, 2*(sparse-0.5)),
	    sparse))
    {
      rand_xform(0.7, 0.9, 0, 2*PI, seed, col, row, ss, tt, xs, xt);
      retval = 1;
    }

  return retval;
}

/***** Displacement function ***************************************
 * ncones: number of bulges in cone
 * spikiness: length of spikes that line top of cone
 * minrad, maxrad: minimum and maximum radii of cone
 * fuzz: blur between barnacle and background
 * seed: controls random attributes
 * s, t: texture coordinates
 *
 * return the displacement for a barnacle
 */
float draw_barnacle_displace(uniform float ncones;
		       float spikiness;
		       float minrad, maxrad, fuzz;
		       float seed;
		       float s, t;)
{
  float layer_disp, layer_opac;
  float bot_rad=0, top_rad=0;
  float r=0, theta=0, thfactor=0;

  barnacle_radii(ncones, minrad, maxrad, seed,
		 xtranslate(0.5, s), xtranslate(0.5, t),
		 bot_rad, top_rad, r, theta, thfactor);

  layer_opac = draw_cone(setp(0.5,0.5,0), bot_rad, top_rad, fuzz, s, t);

  /* distort cone to look like several cones */
  layer_disp = layer_opac + layer_opac *
    spikiness*abs(snoise(theta*thfactor + RN(102)));

  /* ridges */
  layer_disp += layer_opac * 0.5*abs(snoise(r*10/bot_rad + RN(106)));

  /* subtract out the middle, so it looks like mini volcano */
  layer_disp *= 1-(draw_circle(setp(0.5,0.5,0), minrad*2, fuzz, s, t));

  /* add mound to middle */
  layer_disp = max(layer_disp, cos(clamp(r/maxrad*0.7*PI, 0, PI)));

  /* take out lip */
  layer_disp -= minrad*(draw_line(setp(0.5,0.5+minrad*2,0),
				  setp(0.5,0.5-minrad*2,0),
				  fuzz, minrad/3, s, t));

  return layer_disp;
}

/***** color function ***************************************
 * ncones: number of bulges in cone
 * minrad, maxrad: minimum and maximum radii of cone
 * fuzz: blur between barnacle and background
 * seed: controls random attributes
 * s, t: texture coordinates
 * opacity: returned opacity at s, t
 *
 * return the color for a barnacle
 */
color draw_barnacle_color(uniform float ncones;
		     float minrad, maxrad, fuzz;
		     float seed;
		     float s, t;
		     output float opacity)
{
  color layer_color, surface_color;
  float layer_opac;
  float bot_rad, top_rad;
  float r, theta, thfactor;

  surface_color = 0;
  layer_color = 0;
  layer_opac = 0;
  opacity = 0;

  barnacle_radii(ncones, minrad, maxrad, seed,
		 xtranslate(0.5, s), xtranslate(0.5, t),
		 bot_rad, top_rad, r, theta, thfactor);

  /*********** outside color *************************/	 

  layer_color = hsvtorgb(udn(RN(8007), 0.1, 0.2),
			 udn(RN(8009), 0.1, 0.3),
			 udn(RN(8011), 0.8, 1));
  layer_opac = draw_circle(setp(0.5,0.5,0), bot_rad-fuzz, fuzz, s, t);
  surface_color = blend(surface_color, layer_color, layer_opac);

  opacity = layer_opac;

  /*********** inside color *************************/

  layer_color = hsvtorgb(udn(RN(8014), 0.1, 0.2),
			 udn(RN(8017), 0.1, 0.3),
			 udn(RN(8019), 0.4, 0.6));

  layer_opac = 1-draw_circle(setp(0.5,0.5,0), minrad*2, minrad*2, s, t);
  surface_color = blend(surface_color, layer_color, layer_opac);

  return surface_color;
}

#endif /* __BARNACLE_H__ */

