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

// example for a channel shader with access to basechannel
// using standard GUI elements

#include "c4d.h"
#include "c4d_symbols.h"
#include "Xbitmapdistortion.h"

class BitmapData : public ShaderData
{
	public:
		AutoAlloc<BaseChannel> bc;
		Real noise,scale,octaves;
	public:
		virtual Bool Init		(GeListNode *node);
		virtual void Free		(GeListNode *node);
		virtual Bool Read		(GeListNode *node, HyperFile *hf, LONG level);
		virtual Bool Write	(GeListNode *node, HyperFile *hf);
		virtual Bool Message(GeListNode *node, LONG type, void *data);
		virtual Bool CopyTo	(NodeData *dest, GeListNode *snode, GeListNode *dnode, LONG flags, AliasTrans *trn);
		virtual	Vector Output		(PluginShader *chn, ChannelData *cd);

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

		virtual Bool GetDParameter(GeListNode *node, const DescID &id,GeData &t_data,LONG &flags);
		virtual Bool SetDParameter(GeListNode *node, const DescID &id,const GeData &t_data,LONG &flags);

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


Bool BitmapData::GetDParameter(GeListNode *node, const DescID &id,GeData &t_data,LONG &flags)
{
	switch (id[0].id)
	{
		case BITMAPDISTORTIONSHADER_TEXTURE: 
		{
			TexGroupStruct tgs;
			tgs.Init(bc);
			t_data = GeData(CUSTOMDATATYPE_TEXGROUP,tgs); flags |= DESCFLAGS_PARAM_GET; break;																
		}
	}
	
	return TRUE;
}

Bool BitmapData::SetDParameter(GeListNode *node, const DescID &id,const GeData &t_data,LONG &flags)
{
	switch (id[0].id)
	{
		case BITMAPDISTORTIONSHADER_TEXTURE: flags |= DESCFLAGS_PARAM_SET; break;
	}

	return TRUE;
}

Bool BitmapData::Init(GeListNode *node)
{
	if (!bc) return FALSE;

	BaseContainer *data = ((PluginShader*)node)->GetDataInstance();
	
	data->SetReal(BITMAPDISTORTIONSHADER_NOISE,0.0);
	data->SetReal(BITMAPDISTORTIONSHADER_OCTAVES,1.0);
	data->SetReal(BITMAPDISTORTIONSHADER_SCALE,1.0);

	bc->Attach(node);

	return TRUE;
}

void BitmapData::Free(GeListNode *node)
{
}

Vector BitmapData::Output(PluginShader *chn, ChannelData *cd)
{
	Vector uv=cd->p;

	if (noise>0.0)
	{
		Real    scl = 5.0*scale;
		Vector  res = Vector(Turbulence(uv*scl,octaves,TRUE),Turbulence((uv+Vector(0.34,13.0,2.43))*scl,octaves,TRUE),0.0);
		uv.x  = Mix(uv.x,res.x,noise);
		uv.y  = Mix(uv.y,res.y,noise);
	}

	return bc->Sample(cd->vd,&uv,&cd->d,&cd->n,cd->t,cd->texflag,cd->off,cd->scale);
}

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

  // cache values for fast access
	noise   = data->GetReal(BITMAPDISTORTIONSHADER_NOISE);
	octaves = data->GetReal(BITMAPDISTORTIONSHADER_OCTAVES);
	scale   = data->GetReal(BITMAPDISTORTIONSHADER_SCALE);

	return bc->InitTexture(irs);
}

void BitmapData::FreeRender(PluginShader *chn)
{
	bc->FreeTexture();
}

Bool BitmapData::CopyTo(NodeData *dest, GeListNode *snode, GeListNode *dnode, LONG flags, AliasTrans *trn)
{
	BitmapData *dst = (BitmapData*)dest;
	return bc->CopyTo(dst->bc,0,NULL);
}

Bool BitmapData::Read(GeListNode *node, HyperFile *hf, LONG level)
{
	hf->ReadChannel(bc);
	return TRUE;
}

Bool BitmapData::Write(GeListNode *node, HyperFile *hf)
{
	hf->WriteChannel(bc);
	return TRUE;
}

Bool BitmapData::Message(GeListNode *node, LONG type, void *data)
{
	if (type==MSG_GETALLSTRINGS || type==MSG_RENAMETEXTURES ) // send this message to ALL basechannel groups
		return bc->Message(type,data);		

	return TRUE;
}

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

Bool RegisterBitmap(void)
{
	// decide by name if the plugin shall be registered - just for user convenience
	String name=GeLoadString(IDS_BITMAPDISTORTION); if (!name.Content()) return TRUE;
	return RegisterShaderPlugin(ID_BITMAPDISTORTION,name,0,BitmapData::Alloc,"Xbitmapdistortion",0);
}

