/////////////////////////////////////////////////////////////
// CINEMA SDK : SHADER																		 //
/////////////////////////////////////////////////////////////
// VERSION    : CINEMA 4D																	 //
/////////////////////////////////////////////////////////////
// (c) 1989-2002 MAXON Computer GmbH, all rights reserved	 //
/////////////////////////////////////////////////////////////

// example for an easy implementation of a channel shader

#include "c4d.h"
#include "c4d_symbols.h"
#include "Xmandelbrot.h"

#define CCOUNT 125

class MandelbrotData : public ShaderData
{
	public:
		LONG offset;	
		Bool object_access;
		Vector *colors;
	public:
		virtual Bool Init		(GeListNode *node);
		virtual	Vector Output(PluginShader *chn, ChannelData *cd);

		virtual	LONG InitRender(PluginShader *sh, InitRenderStruct *irs);
		virtual	void FreeRender(PluginShader *sh);

		static NodeData *Alloc(void) { return gNew MandelbrotData; }
};

Bool MandelbrotData::Init(GeListNode *node)
{
	BaseContainer *data = ((PluginShader*)node)->GetDataInstance();
	data->SetLong(MANDELBROTSHADER_COLOROFFSET,100);
	data->SetBool(MANDELBROTSHADER_OBJECTACCESS,FALSE);
	colors=NULL;
	return TRUE;
}

LONG MandelbrotData::InitRender(PluginShader *sh, InitRenderStruct *irs)
{
	BaseContainer *data = sh->GetDataInstance();

	colors = (Vector*)GeAlloc(sizeof(Vector)*CCOUNT);
	if (!colors) return LOAD_NOMEM;

	LONG i,r,g,b;
	for (r=g=b=0.0,i=0;i<CCOUNT;i+=1)
	{
		colors[i]=Vector(r/4.0,g/4.0,b/4.0);
		r+=1;
		if(r>4)
		{
			r=0;
			g+=1;
			if(g>4)
			{
				g=0;
				b+=1;
				if(b>4) b=0;
			}
		}
	}

	offset = data->GetLong(MANDELBROTSHADER_COLOROFFSET);
	object_access = data->GetBool(MANDELBROTSHADER_OBJECTACCESS);

	return LOAD_OK;
}

void MandelbrotData::FreeRender(PluginShader *sh)
{
	GeFree(colors);
}

static LONG Calcpix(Real r_min, Real i_min, Real border, LONG depth)
{
	LONG z;
	Real rz,iz,rq,iq;

	rz=r_min;
	iz=i_min;
	z=0;

	do
	{
		iq=iz*iz;
		rq=rz*rz;
		if((rq+iq)>border) return z;
		iz=((rz*iz)*2.0)+i_min;
		rz=rq-iq+r_min;
	} while (++z<depth);

	return z;
}

Vector MandelbrotData::Output(PluginShader *chn, ChannelData *cd)
{
	Real px=(cd->p.x*4.5)-2.5;
	Real py=(cd->p.y*3.0)-1.5;

	LONG i=Calcpix(px,py,5.0,50);
	Vector col = colors[(i+offset)%CCOUNT];

	if (cd->vd && object_access)
	{
		Real r,s,t;
		
		cd->vd->GetRS(cd->vd->lhit,cd->vd->p,&r,&s);

		t=1.0-(r+s);
		r=FMin(r,s);
		r=FMin(r,t);
		r=Smoothstep(0.0,0.3,r);

		col *= r + (1.0-r)*0.5*(Turbulence(cd->vd->p*0.1,4.0,FALSE)+1.0);
	}
	return col;
}

// be sure to use a unique ID obtained from www.plugincafe.com
#define ID_MANDELBROT	1001162

Bool RegisterMandelbrot(void)
{
	// decide by name if the plugin shall be registered - just for user convenience
	String name=GeLoadString(IDS_MANDELBROT); if (!name.Content()) return TRUE;
	return RegisterShaderPlugin(ID_MANDELBROT,name,0,MandelbrotData::Alloc,"Xmandelbrot",0);
}

