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

#ifndef __C4DTOOLS_H
#define __C4DTOOLS_H

#include "ge_math.h"
#include "operatingsystem.h"

#ifndef __API_INTERN__
	#include "c4d_string.h"
	#include "c4d_raytrace.h"
	#include "c4d_shader.h"
	#include "c4d_videopostplugin.h"
#endif

#define COLOR	         255.99 // converting from vectors to integers
#define PERCENT        100.00
#define THIRD          0.333333333333333333
#define SIXTH          0.166666666666666666

#define MAXRANGE	     1.0e20			// maximum value for metric data
#define MAXELEMENTS	   100000000	// maximum number of points
#define MIN_EPSILON    0.001			// epsilon value

class Filename;

inline SVector Mix(const SVector &v1, const SVector &v2, SReal t)	// mixes v1 with v2 dependent on 0<= x <= 1.0
{
	return v1 + t*(v2-v1);
}

inline LVector Mix(const LVector &v1, const LVector &v2, LReal t)	// mixes v1 with v2 dependent on 0<= x <= 1.0
{
	return v1 + t*(v2-v1);
}

inline SReal Mix(SReal v1, SReal v2, SReal t)
{
	return v1 + t*(v2-v1);
}

inline LReal Mix(LReal v1, LReal v2, LReal t)
{
	return v1 + t*(v2-v1);
}

inline SReal Step(SReal a, SReal x)
{
	if (x>=a)
		return SCO 1.0;
	else
		return SCO 0.0;
}

inline LReal Step(LReal a, LReal x)
{
	if (x>=a)
		return 1.0;
	else
		return 0.0;
}

// Attention: Order of parameters different to Peachey's definition
inline SReal Clamp(SReal a, SReal b, SReal x)
{
	return x<a?a:(x>b?b:x);
}

inline LReal Clamp(LReal a, LReal b, LReal x)
{
	return x<a?a:(x>b?b:x);
}

inline SReal Boxstep(SReal a, SReal b, SReal x)
{
	if (b==a) { if (x<a) return SCO 0.0; else return SCO 1.0; }
	x = (x-a)/(b-a);
	return x<SCO 0.0?SCO 0.0:(x>SCO 1.0?SCO 1.0:x);
}

inline LReal Boxstep(LReal a, LReal b, LReal x)
{
	if (b==a) { if (x<a) return 0.0; else return 1.0; }
	x = (x-a)/(b-a);
	return x<0.0?0.0:(x>1.0?1.0:x);
}

inline SReal Smoothstep(SReal a, SReal b, SReal x)
{
	if (x< a) return SCO 0.0;
	if (x>=b) return SCO 1.0;

	x = (x-a)/(b-a); // normalize to [0,1]

	return x*x*(SCO 3.0-SCO 2.0*x);
}

inline LReal Smoothstep(LReal a, LReal b, LReal x)
{
	if (x< a) return 0.0;
	if (x>=b) return 1.0;

	x = (x-a)/(b-a); // normalize to [0,1]

	return x*x*(3.0-2.0*x);
}

inline SReal Modulo(SReal a, SReal b)
{
	if (b==0.0) return 0.0;
	LONG n = (LONG) (a/b);

	a -= n*b;
	if (a<0.0) a+= b;

	return a;
}

inline LReal Modulo(LReal a, LReal b)
{
	if (b==0.0) return 0.0;
	LONG n = (LONG) (a/b);

	a -= n*b;
	if (a<0.0) a+= b;

	return a;
}

inline LONG LModulo(LONG a, LONG b)
{
	if (!b) return 0;
	if (a >= 0) return a%b;

	a -= (a/b)*b;
	if (a<0) a+= b;

	return a;
}

inline LLONG LModulo(LLONG a, LLONG b)
{
	if (!b) return 0;
	if (a >= 0) return a%b;

	a -= (a/b)*b;
	if (a<0) a+= b;

	return a;
}

inline SReal Bias(SReal b, SReal x)
{
  return Pow(x,SReal(-Ln(b)/SCO 0.693147180559945309));
}

inline LReal Bias(LReal b, LReal x)
{
	return Pow(x,LReal(-Ln(b)/0.693147180559945309));
}

inline SVector CutColor(const SVector &v)
{
	SVector r;
	if (v.x>SCO 1.0) r.x=SCO 1.0; else if (v.x<SCO 0.0) r.x=SCO 0.0; else r.x = v.x;
	if (v.y>SCO 1.0) r.y=SCO 1.0; else if (v.y<SCO 0.0) r.y=SCO 0.0; else r.y = v.y;
	if (v.z>SCO 1.0) r.z=SCO 1.0; else if (v.z<SCO 0.0) r.z=SCO 0.0; else r.z = v.z;
	return r;
}

inline LVector CutColor(const LVector &v)
{
	LVector r;
	if (v.x>1.0) r.x=1.0; else if (v.x<0.0) r.x=0.0; else r.x = v.x;
	if (v.y>1.0) r.y=1.0; else if (v.y<0.0) r.y=0.0; else r.y = v.y;
	if (v.z>1.0) r.z=1.0; else if (v.z<0.0) r.z=0.0; else r.z = v.z;
	return r;
}

inline SReal Truncate(SReal x)
{
	if (x>=SCO 0.0)
		return Floor(x);
	else
		return Ceil(x);
}

inline LReal Truncate(LReal x)
{
	if (x>=0.0)
		return Floor(x);
	else
		return Ceil(x);
}

inline Bool VectorEqual(const SVector &v1, const SVector &v2, SReal epsilon=SCO 0.01)
{
	return (Abs(v1.x-v2.x)<epsilon && Abs(v1.y-v2.y)<epsilon && Abs(v1.z-v2.z)<epsilon);
}

inline Bool VectorEqual(const LVector &v1, const LVector &v2, LReal epsilon=0.01)
{
	return (Abs(v1.x-v2.x)<epsilon && Abs(v1.y-v2.y)<epsilon && Abs(v1.z-v2.z)<epsilon);
}

inline SReal VectorSum(const SVector &v)
{
	return v.x+v.y+v.z;
}

inline LReal VectorSum(const LVector &v)
{
	return v.x+v.y+v.z;
}

inline SReal VectorGray(const SVector &v)
{
	return (v.x+v.y+v.z)*SCO THIRD;
}

inline LReal VectorGray(const LVector &v)
{
	return (v.x+v.y+v.z)*THIRD;
}

inline SReal VectorAngle(const SVector &v1, const SVector &v2)
{
	SReal l=Sqrt((v1*v1)*(v2*v2));
	if (l==SCO 0.0) return SCO 0.0;
  return ACos(v1 * v2 / l);
}

inline LReal VectorAngle(const LVector &v1, const LVector &v2)
{
	LReal l=Sqrt((v1*v1)*(v2*v2));
	if (l==0.0) return 0.0;
  return ACos(v1 * v2 / l);
}

inline SReal VectorMin(const SVector &v)
{
	if (v.x<v.y)
	{
		if (v.z<v.x)
			return v.z;
		else
			return v.x;
	}
	else
	{
		if (v.z<v.y)
			return v.z;
		else
			return v.y;
	}
}

inline SReal VectorMax(const SVector &v)
{
	if (v.x>v.y)
	{
		if (v.z>v.x)
			return v.z;
		else
			return v.x;
	}
	else
	{
		if (v.z>v.y)
			return v.z;
		else
			return v.y;
	}
}

inline LReal VectorMin(const LVector &v)
{
	if (v.x<v.y)
	{
		if (v.z<v.x)
			return v.z;
		else
			return v.x;
	}
	else
	{
		if (v.z<v.y)
			return v.z;
		else
			return v.y;
	}
}

inline LReal VectorMax(const LVector &v)
{
	if (v.x>v.y)
	{
		if (v.z>v.x)
			return v.z;
		else
			return v.x;
	}
	else
	{
		if (v.z>v.y)
			return v.z;
		else
			return v.y;
	}
}

Matrix MatrixMove  (const Vector &t);
Matrix MatrixScale (const Vector &s);
Matrix MatrixRotX  (Real w);
Matrix MatrixRotY  (Real w);
Matrix MatrixRotZ  (Real w);

Vector MatrixToHPB			(const Matrix &m, ROTATIONORDER rot_order);	// calculate euler angles from Matrix
Vector VectorToHPB			(const Vector &p);						// calculate euler angles from vector, bank always 0.0
Matrix HPBToMatrix			(const Vector &hpb, ROTATIONORDER rot_order);	// construct Matrix from euler angles
void   MatrixToRotAxis  (const Matrix &m, Vector *v, Real *w); 	// calculate rotation axis v and angle w from matrix m
Matrix RotAxisToMatrix  (const Vector &v, Real w);	    		// calculate matrix from rotation axis v and angle w
Vector GetOptimalAngle  (const Vector &hpb_old, const Vector &hpb_new, ROTATIONORDER order);	// calculate optimal angles between two angle values
Vector PointLineDistance(const Vector &p0, const Vector &v, const Vector &p);
LVector ReflectRay(const LVector &v, const LVector &n);
Matrix RebuildMatrix(const Matrix &m);

class LMinMax
{
private:
	LVector min,max;
	Bool    used;

public:
	LMinMax(void) { min=MAXREALl; max=MINREALl; used=FALSE; }
	LMinMax(const LVector &v) { min=max=v; used=TRUE; }
	inline void Init(void) { min=MAXREALl; max=MINREALl; used=FALSE; } // reset min and max
	inline void Init(const LVector &v) { min=max=v; used=TRUE; }
	inline void AddPoint(const LVector &p) // add point and recalculate min and max
	{
		if (used)
		{
			if (p.x<min.x) min.x = p.x;
			if (p.y<min.y) min.y = p.y;
			if (p.z<min.z) min.z = p.z;
			if (p.x>max.x) max.x = p.x;
			if (p.y>max.y) max.y = p.y;
			if (p.z>max.z) max.z = p.z;
		}
		else
		{
			min=max=p;
			used = TRUE;
		}
	}
	inline void AddPoints(const LVector &a, const LVector &b) // add point and recalculate min and max
	{
		used = TRUE;
		if (a.x<min.x) min.x = a.x;
		if (a.y<min.y) min.y = a.y;
		if (a.z<min.z) min.z = a.z;
		if (b.x>max.x) max.x = b.x;
		if (b.y>max.y) max.y = b.y;
		if (b.z>max.z) max.z = b.z;
	}
	inline void Set(const LVector& a, const LVector &b)
	{
		used = TRUE;
		min = a;
		max = b;
	}

	inline Bool   Content(void)	const { return used; }
	inline const LVector& GetMin (void) const { extern LVector l_empty; if (used) return min; else return l_empty; }
	inline const LVector& GetMax (void) const { extern LVector l_empty; if (used) return max; else return l_empty; }
	inline LVector GetMp  (void) const { if (used) return (min+max)*0.5; else return 0.0; } // middle between min and max
	inline LVector GetRad (void) const { if (used) return (max-min)*0.5; else return 0.0; } // half distance between min and max
	inline void GetMpRad(LVector *mp, LVector *rad) const { if (used) {*mp = (min+max)*0.5; *rad = max - *mp; } else *mp=*rad=0.0; } // half distance between min and max
};

class SMinMax
{
private:
	SVector min,max;
	Bool    used;

public:
	SMinMax(void) { min=MAXREALs; max=MINREALs; used=FALSE; }
	SMinMax(const SVector &v) { min=max=v; used=TRUE; }
	inline void Init(void) { min=MAXREALs; max=MINREALs; used=FALSE; } // reset min and max
	inline void Init(const SVector &v) { min=max=v; used=TRUE; }
	inline void AddPoint(const SVector &p) // add point and recalculate min and max
	{
		if (used)
		{
			if (p.x<min.x) min.x = p.x;
			if (p.y<min.y) min.y = p.y;
			if (p.z<min.z) min.z = p.z;
			if (p.x>max.x) max.x = p.x;
			if (p.y>max.y) max.y = p.y;
			if (p.z>max.z) max.z = p.z;
		}
		else
		{
			min=max=p;
			used = TRUE;
		}
	}
	inline void AddPoints(const SVector &a, const SVector &b) // add point and recalculate min and max
	{
		used = TRUE;
		if (a.x<min.x) min.x = a.x;
		if (a.y<min.y) min.y = a.y;
		if (a.z<min.z) min.z = a.z;
		if (b.x>max.x) max.x = b.x;
		if (b.y>max.y) max.y = b.y;
		if (b.z>max.z) max.z = b.z;
	}
	inline void Set(const SVector& a, const SVector &b)
	{
		used = TRUE;
		min = a;
		max = b;
	}

	inline Bool   Content(void)	const { return used; }
	inline const SVector& GetMin (void) const { extern SVector s_empty; if (used) return min; else return s_empty; }
	inline const SVector& GetMax (void) const { extern SVector s_empty; if (used) return max; else return s_empty; }
	inline SVector GetMp  (void) const { if (used) return (min+max)*SCO 0.5; else return SCO 0.0; } // middle between min and max
	inline SVector GetRad (void) const { if (used) return (max-min)*SCO 0.5; else return SCO 0.0; } // half distance between min and max
	inline void GetMpRad(SVector *mp, SVector *rad) const { if (used) {*mp = (min+max)*SCO 0.5; *rad = max - *mp; } else *mp=*rad=SCO 0.0; } // half distance between min and max
};

#ifdef __SINGLEPRECISION
	typedef SMinMax MinMax;
#else
	typedef LMinMax MinMax;
#endif


class Random
{
	private:
	  ULONG seed;
	  LONG iset;
	  Real gset;

	public:
		Random(void);

		void Init(ULONG s);

		Real Get01(void);	 // return random value between 0 and +1
		Real Get11(void);	 // return random value between -1 and +1

		Real GetG01(void);	 // return random value between 0 and +1 with gaussian distribution
		Real GetG11(void);	 // return random value between -1 and +1 with gaussian distribution

		LONG GetSeed(void) { return seed; }
};

Vector RGBToHSV(const Vector &col);
Vector HSVToRGB(const Vector &col);
Vector RGBToHSL(const Vector &col);
Vector HSLtoRGB(const Vector &col);

struct RayShaderStackElement
{
	TexList *texture;
	void		*texture_link;
	SReal		visibility;
};

struct MsgGICSExData
{
	LONG			action; // 0: load; 1: save; 2:flush
	Filename  *fn;
	Bool			success;
};

struct MsgGINewData
{
	LONG						action; // 0: Animation Prepass, 1 - Net Cache File Notify, 2 - NET Cache File, 3 - Cache Reload, 10 - Baker State
	VideoPostStruct	*vps;
	Filename				*fn;
	Bool						success;
	LONG						state;
	Real						scale;
};

#ifndef __API_INTERN__

inline Vector TransformColor(const Vector &v, COLORSPACETRANSFORMATION colortransformation) { return C4DOS.Sh->TransformColor(v,colortransformation); }

class Stratified2DRandom
{
	private:
		Stratified2DRandom();
		~Stratified2DRandom();
	public:
		//Bool Init(LONG initial_value, Bool reset) { return (this->*C4DOS.Sh->SNInit)(initial_value,reset); }
		//void GetNext(Real *xx, Real *yy) { (this->*C4DOS.Sh->SNGetNext)(xx,yy); }

		Bool Init(LONG initial_value, Bool reset) { return (C4DOS.Sh->SNInit)(this,initial_value,reset); }
		void GetNext(Real *xx, Real *yy) { (C4DOS.Sh->SNGetNext)(this,xx,yy); }

	static Stratified2DRandom *Alloc(void) { return C4DOS.Sh->SNAlloc(); }
	static void Free(Stratified2DRandom *&rnd) { C4DOS.Sh->SNFree(rnd); rnd=NULL; }
};

inline Real	SNoise(const Vector &p) { return C4DOS.Sh->SNoise(p); }
inline Real	SNoise(const Vector &p, Real t) { return C4DOS.Sh->SNoiseT(p,t); }
inline Real	Noise(const Vector &p) { return C4DOS.Sh->Noise(p); }
inline Real	Noise(const Vector &p, Real t) { return C4DOS.Sh->NoiseT(p,t); }
inline Real	PNoise(const Vector &p, const Vector &d) { return C4DOS.Sh->PNoise(p,d); }
inline Real	PNoise(const Vector &p, Real t, const Vector &d, Real dt) { return C4DOS.Sh->PNoiseT(p,t,d,dt); }
inline Real	Turbulence(const Vector &p, Real oct, Bool abs) { return C4DOS.Sh->Turbulence(p,oct,abs); }
inline Real	Turbulence(const Vector &p, Real t, Real oct, Bool abs)  { return C4DOS.Sh->TurbulenceT(p,t,oct,abs); }
inline Real	WavyTurbulence(const Vector &p, Real t, Real oct, Real start)  { return C4DOS.Sh->WavyTurbulence(p,t,oct,start); }
inline void	InitFbm(Real *table, LONG max_octaves, Real lacunarity, Real h)  { C4DOS.Sh->InitFbm(table,max_octaves,lacunarity,h); }
inline Real	Fbm(Real *table, const Vector &p, Real oct) { return C4DOS.Sh->Fbm(table,p,oct); }
inline Real	Fbm(Real *table, const Vector &p, Real t, Real oct)  { return C4DOS.Sh->FbmT(table,p,t,oct); }
inline Real	RidgedMultifractal(Real *table, const Vector &p, Real oct, Real offset, Real gain)  { return C4DOS.Sh->RidgedMultifractal(table,p,oct,offset,gain); }
inline Real	CalcSpline(Real x, Real *knot, LONG nknots)  { return C4DOS.Sh->CalcSpline(x,knot,nknots); }
inline Vector	CalcSpline(Real x, Vector *knot, LONG nknots)  { return C4DOS.Sh->CalcSplineV(x,knot,nknots); }

#define NOISE_RESOLUTION 1024

inline Real	SNoiseP(Vector p, Real t, LONG t_repeat) { return C4DOS.Sh->SNoiseP(p,t,t_repeat); }
inline Real	TurbulenceP(Vector p, Real t, Real oct, Bool abs, LONG t_repeat) { return C4DOS.Sh->TurbulenceP(p,t,oct,abs,t_repeat); }
inline Real	FbmP(Real *table, Vector p, Real t, Real oct, LONG t_repeat) { return C4DOS.Sh->FbmP(table,p,t,oct,t_repeat); }
inline Real	RidgedMultifractalP(Real *table, Vector p, Real t, Real oct, Real offset, Real gain, LONG t_repeat) { return C4DOS.Sh->RidgedMultifractalP(table,p,t,oct,offset,gain,t_repeat); }

struct DisplaceInfo
{
	DisplaceInfo()
	{
		dispn = NULL;
		displacenum = NULL;
	};
	Vector* dispn;
	LONG* displacenum;
};

struct VolumeData : public BaseVolumeData
{
	private:
		VolumeData();
		~VolumeData();

	public:

	// illumination functions
	void			CalcArea(RayLight *light, Bool nodiffuse, Bool nospecular, Real specular_exponent, const LVector &ray_vector, const LVector &p, const LVector &bumpn, const LVector &orign, RAYBIT raybits, Vector *diffuse, Vector *specular) { C4DOS.Sh->CalcArea(this,light,nodiffuse,nospecular,specular_exponent,ray_vector,p,bumpn,orign,raybits,diffuse,specular); }
	Vector    CalcShadow(RayLight *l, const LVector &p, const LVector &bumpn, const LVector &phongn, const LVector &orign, const LVector &rayv, Bool transparency, const RayHitID &hitid, RAYBIT raybits) { return C4DOS.Sh->CalcShadow(this,l,p,bumpn,phongn,orign,rayv,transparency,hitid,raybits); }

	Bool	    IlluminateSurfacePoint(RayLight *rl, Vector *col, LVector *light_vector, const LVector &p, const LVector &bumpn, const LVector &phongn, const LVector &orign, const LVector &ray_vector, ILLUMINATEFLAGS flags, const RayHitID &hitid, RAYBIT raybits, Bool cosine_cutoff) { return C4DOS.Sh->Illuminate(this,rl,col,light_vector,p,bumpn,phongn,orign,ray_vector,flags,hitid,raybits,cosine_cutoff,NULL); }
	Bool	    IlluminateAnyPoint    (RayLight *rl, Vector *col, LVector *light_vector, const LVector &p, ILLUMINATEFLAGS flags, RAYBIT raybits) { return C4DOS.Sh->Illuminate(this,rl,col,light_vector,p,0.0,0.0,0.0,0.0,flags,RayHitID(),raybits,FALSE,NULL); }

	void			IlluminanceSurfacePoint(IlluminanceSurfacePointData *f, Vector *diffuse, Vector *specular) { C4DOS.Sh->IlluminanceSurfacePoint(this,f,diffuse,specular); }
	Vector    IlluminanceAnyPoint(const LVector &p, ILLUMINATEFLAGS flags, RAYBIT raybits) { return C4DOS.Sh->IlluminanceAnyPoint(this,p,flags,raybits); }
	void	    IlluminanceSimple(Vector *diffuse, Vector *specular, Real exponent, IlluminationModel *model, void *data) { if (data) C4DOS.Sh->Illuminance(this,diffuse,specular,model,data); else C4DOS.Sh->Illuminance1(this,diffuse,specular,exponent); }

	LONG	    GetCurrentCPU(void) { return C4DOS.Sh->GetCurrentCPU(this); }
	LONG	    GetCPUCount(void) { return C4DOS.Sh->GetCPUCount(this); }
	LONG			Obj_to_Num(RayObject *obj) { return C4DOS.Sh->Obj_to_Num(this,obj); }
	RayObject *GetObj(LONG index) { return C4DOS.Sh->GetObj(this,index); }
	LONG	    GetObjCount(void) { return C4DOS.Sh->GetObjCount(this); }
	void	    GetUVW(RayObject *op, LONG uvwind, LONG local_id, PolyVector *uvw) { C4DOS.Sh->GetUVW(this,op,uvwind,local_id,uvw); }
	void	    GetNormals(RayObject *op, LONG local_id, PolyVector *norm) { C4DOS.Sh->GetNormals(this,op,local_id,norm); }
	TexData   *GetTexData(RayObject *op, LONG index) { return C4DOS.Sh->GetTexData(this,op,index); }
	LVector	  GetNormal(RayObject *op, LONG polygon, Bool second) { return C4DOS.Sh->GetNormal(this,op,polygon,second); }
	LONG			GetRayPolyState(RayObject *op, LONG local_id) { return C4DOS.Sh->GetRayPolyState(this,op,local_id); }
	LVector	  GetSmoothedNormal(const RayHitID &hitid, const LVector &p) { return C4DOS.Sh->GetSmoothedNormal(this,hitid,p); }
	Bool      GetRS(const RayHitID &hitid, const LVector &p, Real *r, Real *s) { return C4DOS.Sh->GetRS(this,hitid,p,r,s); }
	void      GetWeights(const RayHitID &hitid, const LVector &p, RayPolyWeight *wgt) { C4DOS.Sh->GetWeights(this,hitid,p,wgt); }
	RayLight  *GetLight(LONG index) { return C4DOS.Sh->GetLight(this,index); }
	LONG	    GetLightCount(void) { return C4DOS.Sh->GetLightCount(this); }
	LONG			Light_to_Num(RayLight *light) { return C4DOS.Sh->Light_to_Num(this,light); }
	void      *GetRayData(LONG i) { return C4DOS.Sh->GetRayData(this,i); }
	RayCamera *GetRayCamera(void) { return (RayCamera*)C4DOS.Sh->GetRayData(this,RAY_CAMERA); }
	RayParameter *GetRayParameter(void) { return (RayParameter*)C4DOS.Sh->GetRayData(this,RAY_PARAMETER); }
	RayEnvironment *GetRayEnvironment(void) { return (RayEnvironment*)C4DOS.Sh->GetRayData(this,RAY_ENVIRONMENT); }
	RayObject *GetRaySky(void) { return (RayObject*)C4DOS.Sh->GetRayData(this,RAY_SKY); }
	RayObject *GetRayForeground(void) { return (RayObject*)C4DOS.Sh->GetRayData(this,RAY_FOREGROUND); }
	RayObject *GetRayBackground(void) { return (RayObject*)C4DOS.Sh->GetRayData(this,RAY_BACKGROUND); }
	void	    GetRay(Real x, Real y, Ray *ray) { C4DOS.Sh->GetRay(this,x,y,ray); }
	LVector   ScreenToCamera(const LVector &p) { return C4DOS.Sh->ScreenToCamera(this,p); }
	LVector   CameraToScreen(const LVector &p) { return C4DOS.Sh->CameraToScreen(this,p); }
	Vector    CalcHardShadow(const LVector &p1, const LVector &p2, CALCHARDSHADOW flags, const RayHitID &last_hit, LONG recursion_id=0, void *recursion_data=NULL) { return C4DOS.Sh->CalcHardShadow(this,p1,p2,flags,last_hit,recursion_id,recursion_data); }
	Vector		GetPointUVW(TexData *tdp, const RayHitID &hit, const LVector &p) { return C4DOS.Sh->GetPointUVW(this,tdp,hit,p); }
	Bool			ProjectPoint(TexData *tdp, const RayHitID &hit, const LVector &p, const LVector &n, Vector *uv)	{ return C4DOS.Sh->ProjectPoint(this,tdp,hit,p,n,uv); }
	void			StatusSetText(const String &str) { C4DOS.Sh->StatusSetText(this,&str); }
	void			StatusSetBar(Real percentage) { C4DOS.Sh->StatusSetBar(this,percentage); }
	void			StatusSetSpinMode(Bool on) { C4DOS.Sh->StatusSetSpinMode(this,on); }
	Vector		CalcVisibleLight(Ray *ray, Real maxdist, Vector *trans) { return C4DOS.Sh->CalcVisibleLight(this,ray,maxdist,trans); }
	void			GetXY(LONG *x, LONG *y, LONG *scale) { C4DOS.Sh->GetXY(this,x,y,scale); }
	void			SetXY(Real x, Real y) { C4DOS.Sh->SetXY(this,x,y); }
	MinMax		GetSceneBoundaries(void) { LVector min, max; MinMax MM; C4DOS.Sh->GetSceneBoundaries(this, min, max); MM.Set(min, max); return MM; }
	void			CopyTo(VolumeData *dst) { C4DOS.Sh->CopyVolumeData(this,dst); }
	void			Init(VolumeData *from) { C4DOS.Sh->InitVolumeData(from,this); }
	void			OutOfMemory(void) { C4DOS.Sh->OutOfMemory(this); }
	Bool			CalcFgBg(Bool foreground, LONG x, LONG y, LONG subx, LONG suby, Vector *color, Real *alpha) { return C4DOS.Sh->CalcFgBg(this,foreground,x,y,subx,suby,color,alpha); }
	Real			GetLightFalloff(LONG falloff, Real inner, Real outer, Real dist) { return C4DOS.Sh->GetLightFalloff(falloff,inner,outer,dist); }
	Bool			TestBreak(void) { return C4DOS.Sh->TestBreak(this); }
	BaseVideoPost* GetVideoPost(LONG nth) { return C4DOS.Sh->FindVideoPost(this,nth,TRUE); }
	BaseVideoPost* FindVideoPost(LONG id) { return C4DOS.Sh->FindVideoPost(this,id,FALSE); }
	VPFragment	**GetFragments(LONG x, LONG y, LONG cnt, VPGETFRAGMENTS flags) { return C4DOS.Sh->VPGetFragments(this,x,y,cnt,flags); }
	Bool			AddLensGlow(LensGlowStruct *lgs, Vector *lgs_pos, LONG lgs_cnt, Real intensity, Bool linear_workflow) { return C4DOS.Sh->AddLensGlow(this,lgs,lgs_pos,lgs_cnt,intensity,linear_workflow); }
	Bool			SampleLensFX(VPBuffer *rgba, VPBuffer *fx, BaseThread *bt) { return C4DOS.Sh->SampleLensFX(this,rgba,fx,bt); }
	LONG			TranslateObjIndex(LONG index, Bool old_to_new) { return C4DOS.Sh->TranslateObjIndex(this,index,old_to_new); }
	Bool			TranslatePolygon(RayObject *op, LONG local_index, Vector *previous_points) { return C4DOS.Sh->TranslatePolygon(this,op,local_index,previous_points); }

	Vector    TraceColor(Ray *ray, Real maxdist, const RayHitID &last_hit, SurfaceIntersection *si) { return C4DOS.Sh->TraceColor(this,ray,maxdist,last_hit,si); }
	Vector    TraceColorDirect(Ray *ray, Real maxdist, LONG raydepth, RAYBIT raybits, const RayHitID &last_hit, LVector *oldray, SurfaceIntersection *si) { return C4DOS.Sh->TraceColorDirect(this,ray,maxdist,raydepth,raybits,last_hit,oldray,si); }
	Bool      TraceGeometry(Ray *ray, Real maxdist, const RayHitID &last_hit, SurfaceIntersection *si)  { return C4DOS.Sh->TraceGeometry(this,ray,maxdist,last_hit,si); }
	Bool      TraceGeometryEnhanced(Ray *ray, Real maxdist, const RayHitID &last_hit, LONG raydepth, RAYBIT raybits, LVector *oldray, SurfaceIntersection *si)  { return C4DOS.Sh->TraceGeometryEnhanced(this,ray,maxdist,last_hit,raydepth,raybits,oldray,si); }
	void  		GetSurfaceData(SurfaceData *cd, Bool calc_illum, Bool calc_shadow, Bool calc_refl, Bool calc_trans, Ray *ray, const SurfaceIntersection &si) { C4DOS.Sh->GetSurfaceData(this,cd,calc_illum,calc_shadow,calc_refl,calc_trans,ray,si); }
	Vector		CentralDisplacePointUV(RayObject *op, LONG local_id, LONG uu, LONG vv) { return C4DOS.Sh->CentralDisplacePointUV(this, op, local_id, uu, vv); }
	Vector		CalcDisplacementNormals(Real par_u, Real par_v, LONG u0, LONG v0, LONG u1, LONG v1, LONG u2, LONG v2, const Vector &a, const Vector &b, const Vector &c, RayObject *op, LONG polynum) { return C4DOS.Sh->CalcDisplacementNormals(this, par_u, par_v, u0, v0, u1, v1, u2, v2, a, b, c, op, polynum); }
	Vector		CentralDisplaceUVGetNormal(RayObject *op, LONG local_id, LONG uu, LONG vv) { return C4DOS.Sh->CentralDisplaceUVGetNormal(this, op, local_id, uu, vv); }
	Bool			GetDisplaceInfo(const RayObject* op, DisplaceInfo& info) { return C4DOS.Sh->GetDisplaceInfo(this, op, info); }
	LONG			GetDisplaceNeighbor(const RayObject* op, LONG local_id, LONG side) { return C4DOS.Sh->GetDisplaceNeighbor(this, op, local_id, side); }

	void			SkipRenderProcess(void) { C4DOS.Sh->SkipRenderProcess(this); }

	Render		*GetRenderInstance(void) { return C4DOS.Sh->GetRenderInstance(this); }

	void			GetDUDV(TexData *tex, const LVector &p, const LVector &phongn, const LVector &orign, const RayHitID &hit, Bool forceuvw, Vector *ddu, Vector *ddv, Bool usetangents) { C4DOS.Sh->GetDUDV(this,tex,p,phongn,orign,hit,forceuvw,ddu,ddv,usetangents); }

	void			InitSurfacePointProperties(TexData *td) { C4DOS.Sh->InitSurfacePointProperties(this,td); }

	Bool			AttachVolumeDataFake(BaseObject *camera, const BaseContainer &renderdata) { return C4DOS.Sh->AttachVolumeDataFake(this,camera,renderdata,NULL); }

	Bool			SaveShaderStack(RayShaderStackElement *&stack, LONG &stack_cnt) { return C4DOS.Sh->SaveShaderStack(this,stack,stack_cnt); }
	Bool			RestoreShaderStack(RayShaderStackElement *stack, LONG stack_cnt) { return C4DOS.Sh->RestoreShaderStack(this,stack,stack_cnt); }

	RayObject *GetRaySky(LONG index) { return C4DOS.Sh->GetSky(this, index); } 
	LONG			GetRaySkyCount(void) { return C4DOS.Sh->GetSkyCount(this); }

	RaySampler *GetRaySampler(void *guid, LONG depth) { return C4DOS.Sh->GetSampler(this, guid, depth); }
	Real			GetRayWeight() { return C4DOS.Sh->GetRayWeight(this); }

	Real			CalcAmbientOcclusion(SurfaceIntersection *si, RaySampler *sampler, Real minlength, Real maxlength, Real index, Bool self, Bool trans, Real weight) { return C4DOS.Sh->CalcAmbientOcclusion(this, si, sampler, minlength, maxlength, index, self, trans, weight); }
	Vector		CalcSubsurfaceScattering(Vector scattering, Vector absorption, Vector diffuse, Real ior) { return C4DOS.Sh->CalcSubsurfaceScattering(this, scattering, absorption, diffuse, ior); }

	LONG			GetStreamCount() { return C4DOS.Sh->GetStreamCount(this); }
	void	    GetStreamRay(LONG stream, Real x, Real y, Ray *ray) { C4DOS.Sh->GetStreamRay(this,stream,x,y,ray); }

	Bool			CalcIndirectIllumination(RayHemisphere *hs, Real weight) { return C4DOS.Sh->CalcIndirectIllumination(this, hs, weight); }

	RayRadianceObject *CreateRadianceMaps() { return C4DOS.Sh->CreateRadianceMaps(this); }
	RayRadianceObject *GetRadianceMaps() { return C4DOS.Sh->GetRadianceMaps(this); }
	Vector  	CalcRadianceValue(Ray *ray, const SurfaceIntersection &si) { return C4DOS.Sh->CalcRadianceValue(this,ray,si); }

	static VolumeData *Alloc(void); // should normally NOT be used
	static void Free(VolumeData *&vd);
};

RayObject *AllocRayObject(LONG tex_cnt);
void FreeRayObject(RayObject *&op);

RayLight *AllocRayLight(BaseDocument *doc, BaseObject *op);
void FreeRayLight(RayLight *&lgt);
Bool IlluminateRayLight(RayLight *rl, Vector *color, LVector *light_vector, const LVector &p, const LVector &n);

class VPBuffer
{
	private:
		VPBuffer();
		~VPBuffer();

	public:
		LONG GetInfo(VPGETINFO type);
		Bool GetLine(LONG x, LONG y, LONG cnt, void *data, LONG bitdepth, Bool dithering);
		Bool SetLine(LONG x, LONG y, LONG cnt, void *data, LONG bitdepth, Bool dithering);

		LONG GetBw(void) { return C4DOS.Sh->VPGetInfo(this,VPGETINFO_XRESOLUTION); }
		LONG GetBh(void) { return C4DOS.Sh->VPGetInfo(this,VPGETINFO_YRESOLUTION); }
		LONG GetBt(void) { return C4DOS.Sh->VPGetInfo(this,VPGETINFO_BITDEPTH); }
		LONG GetCpp(void) { return C4DOS.Sh->VPGetInfo(this,VPGETINFO_CPP); }
		Bool GetVisibleBit(void) { return C4DOS.Sh->VPGetInfo(this,VPGETINFO_VISIBLE); }
};

struct VideoPostStruct : public BaseVideoPostStruct
{
	private:
		VideoPostStruct();
		~VideoPostStruct();
};

class Render
{
	private:
		Render();
		~Render();
	public:
		Bool					AllocateBuffer(LONG id, LONG subid, LONG bitdepth, Bool visible);
		LONG					AllocateBufferFX(LONG id, const String &name, LONG bitdepth, Bool visible);
		VPBuffer			*GetBuffer(LONG id, LONG subid);
		BaseContainer GetRenderData(void);
		void					SetRenderData(const BaseContainer &bc);
		VolumeData		*GetInitialVolumeData(LONG cpu);
		void*					GetPrivateData(void);
		Bool					SetRenderProperty(LONG id, const GeData &dat);
		void					IccConvert(void *data, LONG xcnt, LONG components, Bool inverse);
};

void CalcRestrictionInc(ObjectRestriction *lr, RayObject *op, Bool &nodif, Bool &nospec);


enum BakeTexEnums
{
  // data container
	BAKE_TEX_USE_CAMERA_VECTOR        = 1006, // bool
  BAKE_TEX_USE_POLYSELECTION        = 1007, // bool
	BAKE_TEX_AMBIENT_OCCLUSION        = 1009, // bool
	BAKE_TEX_NORMAL                   = 1010, // bool
	BAKE_TEX_SURFACECOLOR             = 1011, // bool
	BAKE_TEX_COLOR                    = 1012, // bool
	BAKE_TEX_DIFFUSION                = 1013, // bool
	BAKE_TEX_LUMINANCE                = 1014, // bool
	BAKE_TEX_ALPHA                    = 1015, // bool
	BAKE_TEX_ILLUMINATION             = 1016, // bool
	BAKE_TEX_SHADOWS                  = 1017, // bool
	BAKE_TEX_BUMP                     = 1018, // bool
	BAKE_TEX_TRANSPARENCY             = 1019, // bool
	BAKE_TEX_UVMAP                    = 1040, // bool
	BAKE_TEX_REFLECTION               = 1041, // bool
	BAKE_TEX_DISPLACEMENT							= 1042, // bool

  BAKE_TEX_WIDTH                    = 1020, // long
  BAKE_TEX_HEIGHT                   = 1021, // long
  BAKE_TEX_PIXELBORDER              = 1022, // long
  BAKE_TEX_FILL_COLOR               = 1023, // vector
	BAKE_TEX_UV_LEFT                  = 1024, // real
	BAKE_TEX_UV_RIGHT                 = 1025, // real
	BAKE_TEX_UV_TOP                   = 1026, // real
	BAKE_TEX_UV_BOTTOM                = 1027, // real
  BAKE_TEX_SUPERSAMPLING		        = 1030, // long
	BAKE_TEX_USE_BUMP                 = 1031, // bool
	BAKE_TEX_NO_GI                    = 1032, // bool
	BAKE_TEX_CONTINUE_UV              = 1033, // bool
	BAKE_TEX_USE_PHONG_TAG						= 1034, // bool (only needed if BAKE_TEX_CONTINUE_UV is set)
	BAKE_TEX_COLORPROFILE			        = 1035, // color profile
                                   // 1400 to 1500 is reserved
  BAKE_TEX_SHOW_STATUS              = 2000, // bool
  BAKE_TEX_PROGRESS_BITMAP          = 2001, // bool set it TRUE, if you want to show the bitmap in a preview during baking
	BAKE_TEX_GENERATE_UNDO						= 2002, // bool
	BAKE_TEX_PREVIEW									= 2003, // bool

	BAKE_TEX_COLOR_ILLUM              = 2100, // bool
	BAKE_TEX_COLOR_SHADOWS            = 2101, // bool
	BAKE_TEX_COLOR_LUMINANCE          = 2102, // bool
	BAKE_TEX_COLOR_DIFFUSION          = 2103, // bool

	BAKE_TEX_LUMINANCE_DIFFUSION      = 2110, // bool

	BAKE_TEX_ILLUMINATION_SHADOWS     = 2120, // bool

	BAKE_TEX_NORMAL_METHOD            = 2130, // long
		BAKE_TEX_NORMAL_METHOD_OBJECT   = 1,
		BAKE_TEX_NORMAL_METHOD_TANGENT  = 2,
		BAKE_TEX_NORMAL_METHOD_WORLD    = 3,
	BAKE_TEX_NORMAL_FLIP_X            = 2131, // bool
	BAKE_TEX_NORMAL_FLIP_Y            = 2132, // bool
	BAKE_TEX_NORMAL_FLIP_Z            = 2133, // bool
	BAKE_TEX_NORMAL_SWAP_YZ           = 2134, // bool
	BAKE_TEX_NORMAL_SOURCE            = 2135, // link

	BAKE_TEX_SURFACE_ILLUMINATION     = 2140, // bool

	BAKE_TEX_AO_VERTEX_MAP            = 2150, // bool
	BAKE_TEX_AO_SELFINTERSECTION      = 2151, // bool
	BAKE_TEX_AO_VERTEXMAPS            = 2152, // pointer to a BaseContainer that stores all new generated vertex maps

	BAKE_TEX_DISPLACEMENT_SOURCE			= 2160, // link to the source object (high-res)
	BAKE_TEX_DISPLACEMENT_HEIGHT			= 2161, // a pointer to a Real that will receive the Displacement height
	BAKE_TEX_DISPLACEMENT_METHOD			= 2163, // long
		BAKE_TEX_DISPLACEMENT_METHOD_OBJECT							= 0,
		BAKE_TEX_DISPLACEMENT_METHOD_WORLD							= 1,
		BAKE_TEX_DISPLACEMENT_METHOD_TANGENT						= 2,
		BAKE_TEX_DISPLACEMENT_METHOD_INTENSITY					= 3,
		BAKE_TEX_DISPLACEMENT_METHOD_CENTEREDINTENSITY	= 4,
		BAKE_TEX_DISPLACEMENT_METHOD_REDGREEN						= 5,
	BAKE_TEX_DISPLACEMENT_SUBPOLY = 2435, // bool
	BAKE_TEX_DISPLACEMENT_SUBPOLY_SUBDIVISION = 2436, // long
	BAKE_TEX_DISPLACEMENT_SUBPOLY_ROUND = 2437, // bool
	BAKE_TEX_DISPLACEMENT_SUBPOLY_ROUNDCONTOUR = 2438, // bool
	BAKE_TEX_DISPLACEMENT_SUBPOLY_HQREMAPPING = 2439, // bool
	BAKE_TEX_DISPLACEMENT_SUBPOLY_MAPRESULT = 2440, // bool
	BAKE_TEX_DISPLACEMENT_SUBPOLY_KEEPEDGES = 2441, // bool
	BAKE_TEX_DISPLACEMENT_SUBPOLY_DISTRIBUTION = 2442, // bool

	BAKE_TEX_OPTIMAL_MAPPING          = 2200, // long
		BAKE_TEX_OPTIMAL_MAPPING_OFF    = 0,
		BAKE_TEX_OPTIMAL_MAPPING_CUBIC  = 1,
		BAKE_TEX_OPTIMAL_MAPPING_ANGLE  = 2,
  BAKE_TEX_OPTIMAL_MAPPING_RELAXCOUNT = 2207,  // long
	BAKE_TEX_OPTIMAL_MAPPING_PREVIEW  = 2201, // long

	BAKE_TEX_NO_INIT_BITMAP           = 5000, // use this if the MultipassBitmap is already initialized
	BAKE_TEX_AUTO_SIZE                = 5001, // bool
	BAKE_TEX_AUTO_SIZE_MIN            = 5002, // long
	BAKE_TEX_AUTO_SIZE_MAX            = 5003, // long
	BAKE_TEX_AUTO_PIXEL_SIZE          = 5004, // real

	BAKE_TEX_STATUSBAR                = 5005, // string

  BAKE_TEX_DUMMY
};

enum BAKE_STATE
{
	BAKE_STATE_NONE										= 0,
	BAKE_STATE_PREPARE                = 10000,
	BAKE_STATE_GI_PREPASS             = 10001,
	BAKE_STATE_FILL_IMAGE             = 10002,
	BAKE_STATE_COMPLETE               = 10003,
	BAKE_STATE_INITIALIZE             = 10004,

	BAKE_STATE_RESIZENOTIFY           = 19999
} ENUM_END_LIST(BAKE_STATE);

/*
textag : the texture tag you want to bake (must be assigned to an object)
data : bake parameters - see below
bmp : the destination bitmap, if this points to a MultipassBitmap, it must be initialized with the correct width and height before BakeTexture is called
th : the current thread
texuvw : must be valid, if UVW projection is selected in the tag, ignored otherwise
destuvw : if not NULL, the current projection is transformed into the uvw tag
the only allowed modes for multipass bitmaps are COLORMODE_RGB, COLORMODE_RGBA, COLORMODE_RGBw, COLORMODE_RGBAw, COLORMODE_RGBf, COLORMODE_RGBAf
MultipassBitmaps must be used if BAKE_TEX_AMBIENT_OCCLUSION is set
*/

struct BakeProgressInfo
{
	BakeProgressInfo() { private_data=NULL; state=BAKE_STATE_NONE; data=NULL; timedelta=0; r=0.0; starttime=0; version = 2; }
	LONG version;
	void* private_data;
	BAKE_STATE state;
	void* data; // data is only used in case of a BAKE_STATE_RESIZENOTIFY message
	LONG timedelta;
	Real r;
	LONG starttime; // the milliseconds when baking started
};

struct BakeTextureResizeNotify
{
	LONG w, h;
	BaseBitmap **cake;
	Bool result;
};

class GeCipher256
{
private:
	void* hnd;
public:
	GeCipher256();
	~GeCipher256();

	Bool Open(const void *key, LONG klength, Bool stream);
	void Close();
	void Encrypt(void *mem, LONG size);
	void Decrypt(void *mem, LONG size);
};


BAKE_TEX_ERR BakeTexture(BaseDocument* doc, const BaseContainer &data, BaseBitmap *bmp, BaseThread* th, BakeProgressHook* hook, BakeProgressInfo* info); // data may not be deleted during baking
BaseDocument* InitBakeTexture(BaseDocument* doc, TextureTag* textag, UVWTag* texuvw, UVWTag* destuvw, const BaseContainer &bc, BAKE_TEX_ERR* err = NULL, BaseThread* th = NULL);
BaseDocument* InitBakeTexture(BaseDocument* doc, TextureTag** textags, UVWTag** texuvws, UVWTag** destuvws, LONG cnt, const BaseContainer &bc, BAKE_TEX_ERR* err = NULL, BaseThread* th = NULL);
#endif

#endif
