/*
Save this file as "mossGenPlug.cpp". Compile using Cutter.
To use this rslplugin in a shader source code file,
-----------------------------------------------------------

-----------------------------------------------------------
For RenderMan Studio
Put the compiled plugin into your maya/projects/RMS_rslplugin directory.
In your maya/projects/RMS_ini/slim.ini file set the ShaderCompiler pref
as follows,
SetPref ShaderCompiler "shader -I[GetEnv HOME]/maya/projects/RMS_rslplugins -I%I -%D -C %f"
or use this,
SetPref ShaderCompiler [list $RMANTREE/bin/shader \
-I[GetEnv HOME]/maya/projects/RMS_rslplugins \
-I$RMSTREE/lib/shaders \
-I$RMSTREE/lib/slim/include \
-I$RMSTREE/lib/rfm/rsl \
-C %f]
Also, add the same directory (ie. "maya/projects/RMS_rslplugins") to the 
workspace's "shader" search path.


Kristen Eggleston
March 2013

built on

Malcolm Kesson's Average Opacity
March 2010


Requires perlin.h
*/

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "/opt/pixar/RenderManProServer-17.0/include/RslPlugin.h"
#include "perlin.h"

extern "C" {

static FILE *file = NULL;
 
static int	 count = 0;

RixMutex *dataLock = NULL;

//-------------------------------------
// init
//-------------------------------------
// Called at startup
void init(RixContext *ctx) 
{ 
srand(1);
RixThreadUtils *lockFactory = (RixThreadUtils *)ctx->GetRixInterface(k_RixThreadUtils);
dataLock = lockFactory->NewMutex();

}

//-------------------------------------
// cleanup
//-------------------------------------
// Called at shutdown
void cleanup(RixContext *ctx) 
{ 
if(dataLock) 
	delete dataLock;
fflush(file);
fclose(file);
}

float randBetween(float min, float max)
{
	float r = ((double)rand()) / (RAND_MAX);
	return (max - min) * r + min;
}
//-------------------------------------
// MossGenPlug
//-------------------------------------
// Main function
RSLEXPORT int hair (RslContext* rslContext, int argc, const RslArg* argv[])
{
//gather input from shader
RslFloatIter 	diffuseArg(argv[1]);
RslFloatIter 	minlenArg(argv[2]);
RslFloatIter 	maxlenArg(argv[3]);
RslFloatIter 	widthArg(argv[4]);
RslFloatIter	noiseDistArg(argv[5]);

RslPointIter 	posArg(argv[6]);
RslPointIter 	normArg(argv[7]);
RslStringIter 	fileName(argv[8]);
RslPointIter 	baseColorArg(argv[9]);
RslPointIter 	tipColorArg(argv[10]);

dataLock->Lock();

//open file and write out that the curves are bezier curves
if(file == NULL) {
	srand(1);
	file = fopen(*fileName, "w");
	fprintf(file, "# srand()\n");
	//fprintf(file, "Basis \"b-spline\" 1 \"b-spline\" 1\n");
	fprintf(file, "Basis \"bezier\" 3 \"bezier\" 3\n");
	}
int numVals = argv[0]->NumValues();

//initialize variables
float diff,min,max,p1x,p1y,p1z,p2x,p2y,p2z,p3x,p3y,p3z,nx,ny,nz,endx,endy,endz,width;
//float noiseDist = *noiseDistArg;

//run through all the points
for (int i = 0; i < numVals; ++i) {
	diff = *diffuseArg;
	min = *minlenArg;
	max = *maxlenArg;
	width = *widthArg;
	
	p1x = (*posArg)[0];
	p1y = (*posArg)[1];
	p1z = (*posArg)[2];
	
	nx = (*normArg)[0];
	ny = (*normArg)[1];
	nz = (*normArg)[2];
	count++;
	
	++diffuseArg;
	++minlenArg;
	++maxlenArg;
	++widthArg;
	++posArg;
	++normArg;
	//-----------------------------------------------------------------
	// scale according to diffuse brightness
	endx = p1x;
	endy = p1y;
	endz = p1z;

	//set up variables for Y
	float baseY = p1y;
	float tipY = p1y + ny * diff * 0.5;
	float incrY = (tipY - baseY)/3;
		
	//set up point 2 variables	
	p2x = p3x = p1x;
	p2z = p3z = p1z;
		
	//set up point 3 variables
	p2y = p1y + incrY;
	p3y = p1y + incrY * 2;
		
	
	float r = ((double)rand()) / (RAND_MAX);
	// Jitter in x and z
	float xamplitude = 0.01;
	float zamplitude = 0.01;
	if(r < 0.25) {
		p2x += (pnoise(p2x, p2y, p2z) + 1) * xamplitude;
		p2z += (pnoise(p2y, p2x, p2z) + 1) * zamplitude;
			
		p3x -= (pnoise(p2x, p2y, p2z) + 1) * xamplitude;
		p3z -= (pnoise(p3z, p3x, p3x) + 1) * zamplitude;
			
		endx -= (pnoise(endx, endy, endz) + 1) * xamplitude;
		endz += (pnoise(endy, endx, endz) + 1) * zamplitude;
		}
	else if(r < 0.5 ) {
		p2x += (pnoise(p2x, p2y, p2z) + 1) * xamplitude;
		p2z -= (pnoise(p2y, p2x, p2z) + 1) * zamplitude;
			
		p3x += (pnoise(p2x, p2y, p2z) + 1) * xamplitude;
		p3z -= (pnoise(p3z, p3x, p3x) + 1) * zamplitude;
			
		endx += (pnoise(endx, endy, endz) + 1) * xamplitude;
		endz += (pnoise(endy, endx, endz) + 1) * zamplitude;
		}
	else if(r < 0.75) {
		p2x += (pnoise(p2x, p2y, p2z) + 1) * xamplitude;
		p2z -= (pnoise(p2y, p2x, p2z) + 1) * 0.02;
			
		p3x -= (pnoise(p2x, p2y, p2z) + 1) * xamplitude;
		p3z += (pnoise(p3z, p3x, p3x) + 1) * zamplitude;
			
		endx -= (pnoise(endx, endy, endz) + 1) * xamplitude;
		endz -= (pnoise(endy, endx, endz) + 1) * 0.02;
		}
	else
		{
		p2x -= (pnoise(p2x, p2y, p2z) + 1) * xamplitude;
		p2z -= (pnoise(p2y, p2x, p2z) + 1) * zamplitude;					

		p3x += (pnoise(p3x, p3y, p3z) + 1) * xamplitude;
		p3z += (pnoise(p3z, p3x, p3x) + 1) * zamplitude;	
			
		endx += (pnoise(endx, endy, endz) + 1) * xamplitude;	
		endz -= (pnoise(endy, endx, endz) + 1) * zamplitude;	
		}	
	endy = tipY;
		
	float baseR = (*baseColorArg)[0];
	float baseG = (*baseColorArg)[1];
	float baseB = (*baseColorArg)[2];
	
	float tipR = (*tipColorArg)[0];
	float tipG = (*tipColorArg)[1];
	float tipB = (*tipColorArg)[2];
	fprintf(file, "Curves \"cubic\" [4] \"nonperiodic\" ");
	fprintf(file, "\"P\" [%1.3f %1.3f %1.3f  %1.3f %1.3f %1.3f  %1.3f %1.3f %1.3f  %1.3f %1.3f %1.3f] \n", p1x,p1y,p1z,  p2x,p2y,p2z, p3x,p3y,p3z, endx,endy,endz);
	//fprintf(file, "\"N\" [%1.3f %1.3f %1.3f  %1.3f %1.3f %1.3f] \n", p1x,0,p1z, endx,0,endz);
	fprintf(file, "\"Cs\" [%1.3f %1.3f %1.3f  %1.3f %1.3f %1.3f] \n", baseR,baseG,baseB,tipR,tipG,tipB);
	fprintf(file, "\"width\" [%1.3f %1.3f]\n", width, width/3);
	}
dataLock->Unlock();

return 0;
}

static RslFunction myFunctions[] = {
    { "void hair(float,float,float,float,float,point,normal,string,point,point)", hair,init,cleanup },
    NULL
	};
RSLEXPORT RslFunctionTable RslPublicFunctions = myFunctions;
};  // extern "C"








