/* Copyright (c) 2001, Chris Lynch/Artdream Designs 
 * 
 * All rights reserved.
 * 
 * Contact:      chris@artdreamdsigns.com
 * Information:  http://www.artdreamdesigns.com
 *
 * This is a C implementation of the BMRT greenmarble shader written by Larry
 * Gritz. The main difference is that Renderman functions such as specular,
 * ambient, etc. have been removed. This plugin will return only color values.
 * It could also be noted that this shader is not actually only for green marble. 
 * The controls actually allow one to create a marble with a mixture of any two
 * colors plus a third color for the veins. The controls should be pretty self
 * explanatory.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "math.h"
#include "plugin.h"
#include "rm.h"

/* ******************** GLOBAL VARIABLES ***************** */

char name[]= "greenmarble";

/* Subtype names must be less than 15 characters */

#define NR_TYPES	1
char stnames[NR_TYPES][16]= {"Default"};

VarStruct varstr[]= {
	{ NUM|FLO,	"veinfreq",	      	2.05,   1.0, 10.0,  
	   "vein frequency" },
	{ NUM|FLO,	"sharpness",		25.0,  0.0, 50.0,  
	   "sharpness" },
	{ NUM|FLO,	"dark-red",	      	0.39,  0.0, 1.0,   
	   "dark color red "},
	{ NUM|FLO,	"dark-green",		0.29,  0.0, 1.0,   
	   "dark color green "},
	{ NUM|FLO,	"dark-blue",		0.32,  0.0, 1.0,   
	   "dark color blue "},
	{ NUM|FLO,	"lightred",	      	0.51,  0.0, 1.0,   
	   "dark color red "},
	{ NUM|FLO,	"lightgreen",		0.38,  0.0, 1.0,   
	   "dark color green "},
	{ NUM|FLO,	"lightblue",		0.40,  0.0, 1.0,   
	   "dark color blue "},
	{ NUM|FLO,	"vein-red",	      	0.81,  0.0, 1.0,   
	   "vein color red "},
	{ NUM|FLO,	"vein-green",		0.70,  0.0, 1.0,   
	   "vein color green "},
	{ NUM|FLO,	"vein-blue",		0.76,  0.0, 1.0,   
	   "vein color blue "}
};

/* The cast struct is for input in the main doit function
   Varstr and Cast must have the same variables in the same order */

typedef struct Cast {
	float veinfreq;
	float sharpness;
	float darkred;
	float darkgreen;
	float darkblue;
	float lightred;
	float lightgreen;
	float lightblue;
	float veinred;
	float veingreen;
	float veinblue;

} Cast;

/* result:
   Intensity, R, G, B, Alpha, nor.x, nor.y, nor.z
 */

float result[8];

/* cfra: the current frame */

float cfra;

int plugin_tex_doit(int, Cast *, float *, float *, float *);


int plugin_tex_getversion(void) {
	return B_PLUGIN_VERSION;
}

void plugin_but_changed(int but) {
}

void plugin_init(void) {
}

/* this function should not be changed: */

void plugin_getinfo(PluginInfo *info) {
	info->name= name;
	info->stypes= NR_TYPES;
	info->nvars= sizeof(varstr)/sizeof(VarStruct);

	info->snames= stnames[0];
	info->result= result;
	info->cfra= &cfra;
	info->varstr= varstr;

	info->init= plugin_init;
	info->tex_doit=  (TexDoit) plugin_tex_doit;
	info->callback= plugin_but_changed;
}

/* ************************************************************
	GreenMarble
   ************************************************************ */

int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, 
   float *dyt) {
	float Ct[3];
	float darkcolor[3];
	float lightcolor[3];
	float veincolor[3];
        float freq;
        float turbsum, turb, i;
        float dPP;
        float PP[3], PPf[3], tt[3];
        float *tt2;
        float dx[3], dy[3];
        Ct[0]=Ct[1]= 1.0;
        Ct[2] = 0.0;
	darkcolor[0] = cast->darkred;
	darkcolor[1] = cast->darkgreen;
	darkcolor[2] = cast->darkblue;
	veincolor[0] = cast->veinred;
	veincolor[1] = cast->veingreen;
	veincolor[2] = cast->veinblue;
	lightcolor[0] = cast->lightred;
	lightcolor[1] = cast->lightgreen;
	lightcolor[2] = cast->lightblue;

	PP[0] = texvec[0];
	PP[1] = texvec[1];
	PP[2] = texvec[2];

	dPP = MINFILTWIDTH;
	if (dxt) { dx[0] = dxt[0]; dx[1] = dxt[1]; dx[2] = dxt[2];}
	if (dyt) { dy[0] = dyt[0]; dy[1] = dyt[1]; dy[2] = dyt[2];}
	if (dxt && dyt) dPP = filterwidthp(dx, dy);

	turb = 0.5 * RMturbulence (PP, dPP, 5, 2, 0.5);
	tt2 = mix(darkcolor, lightcolor, smoothstep(0.1,0.35,turb));
        Ct[0] = tt2[0];
        Ct[1] = tt2[1];
        Ct[2] = tt2[2];
	free(tt2);
/*
 * Now we layer on the veins
 */

/* perturb the lookup */
        PP[0] += 35.2;
        PP[1] -= 21.9;
        PP[1] += 6.25;
        tt2 = vfBm(PP, dPP, 6, 2, 0.5);
	PP[0] += 0.5 * tt2[0];
	PP[1] += 0.5 * tt2[1];
	PP[2] += 0.5 * tt2[2];
	free(tt2);

/* Now calculate the veining function for the lookup area */

    turbsum = 0;  freq = 1;

	PP[0] = PP[0]*cast->veinfreq;
	PP[1] = PP[1]*cast->veinfreq;
	PP[2] = PP[2]*cast->veinfreq;

    for (i = 0;  i < 3;  i += 1) {
        PPf[0] = PP[0]*freq;
        PPf[1] = PP[1]*freq;
        PPf[2] = PP[2]*freq;
	turb = fabs (filteredsnoise (PPf, dPP*freq));
	turb = pow (smoothstep (0.8, 1, 1 - turb), cast->sharpness) / freq;
	turbsum += (1-turbsum) * turb;
	freq *= 2;
	}
        tt[0] = (PP[0]-4.4) * 2;
        tt[1] = (PP[1]+8.34) * 2;
        tt[2] = (PP[2]+27.1) * 2;
	turbsum *= smoothstep (-0.1, 0.05, snoise(tt));
	tt2 = mix (Ct, veincolor, turbsum);
        Ct[0]=tt2[0];
        Ct[1]=tt2[1];
        Ct[2]=tt2[2];
	free(tt2);

	result[0] = 1.0;
	result[1] = Ct[0];
	result[2] = Ct[1];
	result[3] = Ct[2];
	result[4] = 1.0;

	return 1;
}
