/////////////////////////////////////////////////////////////
// CINEMA 4D SDK                                           //
/////////////////////////////////////////////////////////////
// (c) MAXON Computer GmbH, all rights reserved            //
/////////////////////////////////////////////////////////////

#ifndef __C4D_SHADER_H
#define __C4D_SHADER_H

#include "ge_math.h"
#include "c4d_file.h"
#include "c4d_basetime.h"
#include "ge_prepass.h" // important

#define TEX_TILE							0x01				// texture tile enabled
#define TEX_MIRROR						0x02				// texture mirroring enabled
#define TEX_ALPHA							0x04				// texture uses alpha channel (for use within channel shaders)
#define TEX_BUMP							0x08				// bump calculation

#define GET_TEX_BUMP_SAMPLE(texflag) (((texflag)>>4)&3)
#define GET_TEX_CHANNEL(texflag) (((texflag)>>6)&15)

inline LONG CALC_TEXINFO(LONG texflag, LONG channel) { return (texflag&~0x3f0)|(channel<<6); }
inline LONG CALC_TEXINFO_BUMP(LONG texflag, LONG channel, LONG sample) { return (texflag&~0x3f0)|((sample&3)<<4)|(channel<<6); }

class  CDialog;
class  HyperFile;
class  BaseChannel;
class  BaseDocument;
class  BaseObject;
class  BaseTag;
class  BaseDraw;
class  BaseDrawHelp;
class  BaseThread;
class  Filename;
class  String;
class  BaseView;
class  BaseContainer;
class  Raytracer;
class  RootTextureString;
struct RayObj;
struct RayLight;
struct RayObject;
struct VolumeData;

// channels
#define MAX_MATERIALCHANNELS  14 // channels in C4D material

#define CHANNEL_ANY						-1 // unlabeled plugin channel

#define CHANNEL_COLOR					 0
#define CHANNEL_LUMINANCE			 1
#define CHANNEL_TRANSPARENCY	 2
#define CHANNEL_REFLECTION		 3
#define CHANNEL_ENVIRONMENT		 4
#define CHANNEL_FOG						 5
#define CHANNEL_BUMP					 6
#define CHANNEL_ALPHA					 7
#define CHANNEL_SPECULAR			 8
#define CHANNEL_SPECULARCOLOR	 9
#define CHANNEL_GLOW					10
#define CHANNEL_DISPLACEMENT	11
#define CHANNEL_DIFFUSION			12
#define CHANNEL_NORMAL				13

#define BASECHANNEL_COLOR_EX					1000  // VECTOR
#define BASECHANNEL_BRIGHTNESS_EX			1001  // REAL
#define BASECHANNEL_MIXMODE_EX   			1006	// LONG
#define BASECHANNEL_MIXSTRENGTH_EX		1007	// REAL

#define BASECHANNEL_TEXTURE      			1002  // STRING
#define BASECHANNEL_BLUR_OFFSET  			1003	// REAL
#define BASECHANNEL_BLUR_STRENGTH			1004	// REAL
#define BASECHANNEL_INTERPOLATION			1005	// LONG
#define BASECHANNEL_TIME_FROM    			1008	// LONG
#define BASECHANNEL_TIME_TO      			1009	// LONG
#define BASECHANNEL_TIME_FPS     			1010	// LONG
#define BASECHANNEL_TIME_MODE    			1011	// LONG
#define BASECHANNEL_TIME_TIMING  			1012	// LONG
#define BASECHANNEL_TIME_START   			1013	// BASETIME
#define BASECHANNEL_TIME_END     			1014	// BASETIME
#define BASECHANNEL_TIME_LOOPS   			1015	// LONG
#define BASECHANNEL_SHADERID					1016  // LONG
#define BASECHANNEL_SUGGESTEDFOLDER		1017	// FILENAME

enum INITRENDERFLAG
{
	INITRENDERFLAG_0							= 0,
	INITRENDERFLAG_TEXTURES				= (1<<0),
	INITRENDERFLAG_PAINTERNOMIP		= (1<<1),
	INITRENDERFLAG_NOMIP					= (1<<2),
	INITRENDERFLAG_PREVIEWRENDER	= (1<<3),
	INITRENDERFLAG_IRR						= (1<<4)
} ENUM_END_FLAGS(INITRENDERFLAG);

Vector TransformColor(const Vector &input, COLORSPACETRANSFORMATION colortransformation);

struct InitRenderStruct
{
	InitRenderStruct()
	{
		version=0;
		fps=30;
		docpath=NULL;
		errorlist=NULL;
		matname=NULL;
		vd=NULL;
		doc=NULL;
		thread=NULL;
		flags=INITRENDERFLAG_TEXTURES;
		linear_workflow=FALSE;
		document_colorprofile=DOCUMENT_COLORPROFILE_SRGB;
	}

	explicit InitRenderStruct(BaseDocument *t_doc) { Init(t_doc); }
	
	void Init(BaseDocument *t_doc);
	
	LONG							version;
	BaseTime					time;
	LONG							fps;
	Filename					docpath;
	String						*matname;
	RootTextureString *errorlist;
	VolumeData				*vd;
	BaseDocument			*doc;
	BaseThread				*thread;
	INITRENDERFLAG		flags;
	
	Bool					linear_workflow;	
	LONG					document_colorprofile;
	
	LONG GetThreadCount() const;
	
	Vector TransformColor(const Vector &input) const
	{ 
		if (document_colorprofile==DOCUMENT_COLORPROFILE_SRGB && linear_workflow)
			return ::TransformColor(input,COLORSPACETRANSFORMATION_SRGB_TO_LINEAR);
		else if (document_colorprofile==DOCUMENT_COLORPROFILE_LINEAR && !linear_workflow)
			return ::TransformColor(input,COLORSPACETRANSFORMATION_LINEAR_TO_SRGB);

		return input;
	}
};

// TexData::side
#define SIDE_FRONT_AND_BACK	0
#define SIDE_FRONT					1
#define SIDE_BACK						2

// texture information, read-only
struct TexData
{
	private:
		TexData();
		~TexData();
	public:
		Matrix			m,im;
		CHAR				texflag;
		CHAR				additive,proj,side;
		LONG				restrict;
		Real				ox,oy,lenx,leny,repetitionx,repetitiony;
		GeListNode	*mp;
		LONG				uvwind;
		BaseView		*camera;
		CHAR				uvbump;
		BaseTag			*link;

	static TexData *Alloc();
	static void Free(TexData *&td);
	void Init(void);
};

// ray structure
struct Ray
{
	Ray() : p(DC), v(DC) { ior = 1.0; }
	
	// read and write
	LVector p,v;					// ray position and vector
	Real		ior;					// current index of refraction
	Vector	pp[3];				// 3 additional ray points for MIP-Mapping
	Vector	vv[3];				// 3 additional ray vectors for MIP-Mapping

	// read-only
	Vector	transport;		// current intensity (for special shadow calculation)
};

#define L_SPLIT_BIT	(1<<31)

struct RayHitID
{
private:
	LONG rayobject;
	LONG polygon;

public:
	RayHitID() { rayobject=polygon=0; }
	RayHitID(_DONTCONSTRUCT DC) {}
	RayHitID(const RayHitID &other) { rayobject=other.rayobject; polygon=other.polygon; }
	RayHitID(RayObject *t_rayobject, LONG t_polygon, Bool second) { Set(t_rayobject,t_polygon,second); }

	inline Bool IsEqual(const RayHitID &snd) const { return rayobject==snd.rayobject && polygon==snd.polygon; }

	inline Bool Content() const { return rayobject!=0; }
	inline void Clear() { rayobject=polygon=0; }

#ifdef __API_INTERN__
	void Set(RayObject *t_rayobject, LONG t_polygon, Bool second);
	RayObj *GetObject(Raytracer *rt) const;
	inline LONG GetPolygonPlus() const { return (rayobject&L_SPLIT_BIT)|polygon; }		
#else
	inline void Set(RayObject *t_rayobject, LONG t_polygon, Bool second)
	{
		rayobject = C4DOS.Sh->Obj_to_Num(NULL,t_rayobject)+1;
		polygon   = t_polygon;
		if (second) rayobject|=L_SPLIT_BIT;
	}

	inline RayObject *GetObject(VolumeData *vd) const
	{
		return C4DOS.Sh->ID_to_Obj(vd,*this);
	}
#endif

	inline LONG GetPolygon() const { return polygon; }		
	inline Bool GetSecond() const { return (rayobject&L_SPLIT_BIT)!=0; }		

	inline void ClearSecond() { rayobject&=~L_SPLIT_BIT; }
	inline void SetSecond() { rayobject|=L_SPLIT_BIT; }

	inline void SetPrivateData(LONG t_rayobject, LONG t_polygon) { rayobject = t_rayobject; polygon = t_polygon;}
	inline void GetPrivateData(LONG *t_rayobject, LONG *t_polygon) const { *t_rayobject=rayobject; *t_polygon=polygon; }
};

// intersection structure
struct SurfaceIntersection
{
	SurfaceIntersection() { sid=0; par_u=par_v=0.0; }
	SurfaceIntersection(_DONTCONSTRUCT dc) : id(DC), p(DC), n(DC) {}

#ifdef __API_INTERN__
	RayObj		*op;					// intersected object
#else
	RayObject	*op;					// intersected object
#endif

	RayHitID	id;						// ray hit ID
	LVector 	p,n;					// point and normal
	LONG			sid;					// sub ID, only used for SPD
	Real			par_u,par_v;	// barycentric coordinates, only used for SPD
};

class VPBitmap;

struct Multipass
{
	VPBitmap	**bmp;
	LONG			*ind;
	Real			*result;
	LONG			cnt,cmp;

	Vector		**diffuse;
	LONG			diffuse_cnt;

	Vector		**specular;
	LONG			specular_cnt;

	Vector		**shadow;
	LONG			shadow_cnt;

	RayLight	**light;
	LONG			light_cnt;

	Real			**ochannel;
	LONG			*ochannelid;
	LONG			ochannel_cnt;

	Vector		*vp_ambient,*vp_diffuse,*vp_specular,*vp_shadow,*vp_reflection,*vp_transparency;
	Vector		*vp_radiosity,*vp_caustics,*vp_illumination;
	Vector		*vp_mat_color,*vp_mat_luminance,*vp_mat_transparency,*vp_mat_reflection;
	Vector		*vp_mat_environment,*vp_mat_specularcolor,*vp_atmosphere;
	Real			*vp_depth,*vp_mat_specular,*vp_mat_diffusion,*vp_atmosphere_mul;
	Vector		*vp_ambientocclusion,*vp_mat_uv,*vp_mat_normal,*vp_motionvector;
};

// main volume shader structure
struct BaseVolumeData
{
	protected:
		BaseVolumeData(void);
	public:
		// read-only
		LONG				version;	// version number of structure
		LONG				fps;			// frames per second
		Vector			ambient;	// global ambient component
		Real				time;			// current time in seconds

		// read and write
		// returnable data: color, transparency, reflection, alpha color, transparent and reflectant ray, point and normal
		Vector			col;							// set the calculated color here
		Vector			trans;						// set the calculated transparency here
		Vector			refl;							// set the calculated reflection here
		Real				alpha;						// set the calculated alpha here
		Ray					*tray,*rray;			// read and write the transparency/reflection rays; NEVER change the pointers
		LVector			p;								// surface point - may only be modified by Displace
		LVector			bumpn;						// surface phong & bump normal

		// read-only
		Ray					*ray;							// current eye ray
		LVector			orign;						// original surface normal
		LVector			n;								// surface phong normal
		LVector			dispn;						// suggested displacement direction
		LReal				dist;							// distance from eye to surface point
		LReal				cosc;							// angle beween ray vector and unbumped normal

		Vector			uvw;							// surface uvw coordinates - INVALID for volumetric shaders
		Vector			delta;						// MIP sample radius
		RayHitID		lhit;							// surface identity
		TexData			*tex;							// surface texture, NEVER change pointer
		Vector			ddu,ddv;					// bump mapping basis vectors
		LONG				raydepth;					// depth of actual ray

		LONG				calc_trans;				// specifies, if transparency shall be rendered
		LONG				calc_refl;				// specifies, if reflections shall be rendered
		Bool				calc_shadow;			// specifies, if shadows shall be rendered
		LONG				calc_illum;				// specifies, if illumination shall be rendered
		LONG				calc_mip;					// specifies, if mip calculations shall be done

		Vector			pp[3];						// MIP corner points in global space
		Vector			nn[3];						// MIP normals of the three other corner points

		RAYBIT			raybits;					// ray information
		RayLight		*xlight;					// lightsource during shadow evaluation
		RayObject		*op;							// object

		// read and write
		LONG				recursion_id;			// plugin ID of data passed through recursion
		void				*recursion_data;	// address of data passed through recursion
		Multipass   *multipass;				// to be filled for multipasses

		// read only
		Vector			back_p;						// set VOLUMEINFO_TRANSFORM   (CHANNELINFO_TRANSFORM) to access this value
		Vector			back_delta;				// set VOLUMEINFO_TRANSFORM   (CHANNELINFO_TRANSFORM) to access this value; local space

		Real				global_mip;				// global MIP scale

		LONG				sid;							// subpolygon information: subpolygon and barycentric coordinates
		Real				par_u,par_v;

		// read only
		SurfaceIntersection *intersection; // intersection data (can be NULL)
};

// main channel shader structure
struct ChannelData
{
	ChannelData() { }
	ChannelData(BaseVolumeData *t_vd) : p(t_vd->uvw), n(t_vd->n.ToRV()), d(t_vd->delta) { t=t_vd->time; texflag=0; vd=(VolumeData*)t_vd; off=0.0; scale=t_vd->global_mip; }

	// read-only
	Vector			p;					// texture position in UVW coordinates
	Vector			n;					// surface normal
	Vector			d;					// MIP sample radius in UVW coordinates
	Real				t;					// current time in seconds
	LONG				texflag;		// texture flags
	VolumeData	*vd;				// pointer to volume information, can be NULL
	Real				off,scale;	// blur offset and scale 
};

#define MSG_GETALLASSETS		112004
#define MSG_SHADERV5TOV6		112005
#define MSG_SHADERV6TOV7		112006
#define MSG_SHADERREAD			112009
#define MSG_RENAMETEXTURES	112010

class RootTextureString;

enum ASSETDATA_FLAG
{
	ASSETDATA_FLAG_0									= 0,
	ASSETDATA_FLAG_CURRENTFRAMEONLY	= (1<<0),
	ASSETDATA_FLAG_TEXTURES					= (1<<1),	// only return texture assets
} ENUM_END_FLAGS(ASSETDATA_FLAG);

struct AssetData
{
	AssetData(BaseDocument *t_doc, RootTextureString *t_rts, ASSETDATA_FLAG t_flags)
	{
		doc				= t_doc;
		rs        = t_rts;
		flags     = t_flags;
	}

	BaseDocument			*doc;
	RootTextureString *rs;
	ASSETDATA_FLAG		flags;

	Bool Add(const Filename &fn, BaseList2D *bl);
};

struct RenameTextureMessage
{
	RenameTextureMessage() : doc(NULL), changecnt(0), noundo(FALSE) { }
	Filename oldname;
	Filename newname;
	BaseDocument *doc;
	LONG changecnt;
	Bool noundo;
};

struct VPFragment
{
	RayHitID		id;
	UCHAR 			subx,suby;
	SWORD 			weight;
	RayObject		*op;
	
	SVector			color;

	Real				z;
	Vector			p;
	Vector			n;
	
	VPFragment	*next;
};

struct ShaderReadData
{
	HyperFile			*hf;
	LONG					oldid;
	Real					*data;
	LONG					oldlevel;
	BaseContainer	*oldctr;
};

#endif
