/*
 * Copyright (c) 2001, Armagan YAVUZ
 * based on sample file by NAN
 */

#include <math.h>
#include "t_texture.h"

char name[24]= "t_Wood";

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

#define NR_TYPES	0
/*char stnames[NR_TYPES][16]= {};*/

/* Structure for buttons,
 *  butcode      name           default  min  max  0
 */

VarStruct varstr[]= {
{	NUM|FLO,	"Turbulance",		1.0, 	0.0, 100.0, ""},
{	NUM|FLO,	"Noise Size",		0.25, 	0.0001, 2.0, ""},
{	NUM|INT,	"Noise Depth",		2.0, 	0.0, 6.0, ""},
{	NUM|FLO,	"Detail Size",		0.5, 	0.0001, 1.0, ""},
{ 	TOG|INT,	"Hard Noise",   0.0,	 0.0, 1.0,  ""},
{	NUM|INT,	"Seed",		0.0, 	0.0, 255.0, ""},
{ 	TOG|INT,	"BumpMap",   1.0,	 0.0, 1.0,  
	"Generate bump map"},
{	NUM|FLO,	"Filter",		0.15, 	0.0001, 1.0, 
	"Lower means better accuracy, higher means less artifacts"},
{ 	TOG|INT,	"Double Sample",   0.0,	 0.0, 1.0,  
	"Use slower (and higher quality) bumpmap method"},
{	LABEL|INT,   " ",             0.,    0.,   0.,   ""},
{	NUM|FLO,	"Map Max",		1.0, 	0.0, 1.0, ""},
{	NUM|FLO,	"Map Min",		0.0, 	0.0, 1.0, ""},
{	NUM|FLO,	"Sharpness",		0.0, 	0.0, 1.0, ""},
};

/* The cast struct is for input in the main doit function
   Varstr and Cast must have the same variables in the same order,
   INCLUDING dummy variables for label fields. */

typedef struct Cast {
	float turbulance_weight;
	float noise_size;
	int depth;
	float falloff;
	int hard_noise;
	int seed;
	int do_bump;
	float filter;
	int double_bump;
	int dummy2;
	float map_max;
	float map_min;
	float width;
} 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*);

/* ******************** Fixed functions ***************** */

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= NULL; 
	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;
}

float intensity(int stype, Cast *cast, float x,float y, float z)
{
	float vec[3];
	float res;
	float max;
	float min;
	float t,tt;
	float w;

	point_turbulance(cast->noise_size, cast->falloff, cast->hard_noise, 
		x, y, z, vec, cast->depth,cast->seed);

	x += vec[0] * cast->turbulance_weight;
	y += vec[1] * cast->turbulance_weight;
	z += vec[2] * cast->turbulance_weight;
	t = x + y + z;
	w = cast->width;

	t = (0.5 * (t + 1.0));
	t = t - floorf(t);
	t = (t)* 2.0 - 1.0;

	if (fabs(t) < w)
	{
		res = 1.0;
	}
	else
	{
		tt = fabs(t) - w;
		if (t < 0.0)
			tt = - tt;
		res = ((cos(tt * 3.1415926 * 1.0 * (1.0 / (1.0 - w)))) + 1.0) *
			0.5;
	}

	max = cast->map_max;
	min = cast->map_min;
	if (max <= min)
	{
		max = (max + min) * 0.05;
		min = max - 0.01;
	}
	if (res < min)
		res = 0.0;
	else if (res > max)
		res = 1.0;
	else
		res = (res - min) / (max - min);
	res = CLAMP(res,0.0,1.0);
	return res;

}

#define between(x,a,b) (((a) <= (x))&&((x) < (b)))
#define FRAND (((((float)(((unsigned int)rand()) & 8191)) / 4096.0) - 1.0) * 0.5)

int plugin_tex_doit(int stype, Cast *cast, float *texvec, float *dxt, 
	float *dyt)
{
	float s;
	int i;

	s = cast->noise_size;
  	s = s * cast->filter;
	if (cast->depth > 0)
		s = s * cast->falloff;
	for (i=1; i<cast->depth; i++)
	  s = s * 0.6;
	result[0] = intensity(stype,cast,texvec[0], texvec[1], texvec[2]);
	if (cast->do_bump)
	{
		result[5] = intensity(stype,cast,texvec[0] + s, texvec[1], 
			texvec[2]) - result[0] ;
		result[6] = intensity(stype,cast,texvec[0] , texvec[1] + s, 
			texvec[2]) - result[0] ;
		result[7] = intensity(stype,cast,texvec[0] , texvec[1], 
			texvec[2] + s) - result[0] ;
		if (cast->double_bump)
		{
			result[5] -= intensity(stype,cast,texvec[0] - s, 
				texvec[1], texvec[2]) - result[0] ;
			result[6] -= intensity(stype,cast,texvec[0] , 
				texvec[1] - s, texvec[2]) - result[0] ;
			result[7] -= intensity(stype,cast,texvec[0] , 
				texvec[1], texvec[2] - s) - result[0] ;
			result[5] *= 0.5;
			result[6] *= 0.5;
			result[7] *= 0.5;	
		}
		result[5] *= 0.05 / s;
		result[6] *= 0.05 / s;
		result[7] *= 0.05 / s;
		return 2;
	}
	return 0;
}
