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

#ifndef __C4DTOOLS_H
#define __C4DTOOLS_H

#include "ge_vector.h"
#include "ge_matrix.h"
#include "operatingsystem.h"
#include "c4d_string.h"
#include "c4d_raytrace.h"
#include "c4d_shader.h"
#include "c4d_videopostplugin.h"

#define COLOR	         255.99 // converting from vectors to integers
#define PERCENT        100.00
#define THIRD          0.33333333333333
#define SIXTH          0.16666666666666

#define MAXRANGE	     10000000.0 // maximum value for points, vectors...
#define MAXELEMENTS	   100000000 // maximum number of points
#define MINSIZE        0.001	 // epsilon value

class Filename;

// Also called 'LERP'
inline Vector Mix(const Vector &v1, const Vector &v2, Real t)	// mixes v1 with v2 dependent on 0<= x <= 1.0
{
	return v1 + t*(v2-v1);
}

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

// Also called 'LERP'
inline Real Mix(Real v1, Real v2, Real t)
{
	return v1 + t*(v2-v1);
}

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

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

inline Real Pulse(Real a, Real b, Real x)
{
	if (x>=a && x<=b)
		return 1.0;
	else
		return 0.0;
}

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

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

inline Real Boxstep(Real a, Real b, Real 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 LReal LBoxstep(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 Real Smoothstep(Real a, Real b, Real 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 LReal LSmoothstep(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 Real Modulo(Real a, Real 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 Real Gammacorrect(Real gamma, Real x)
{
	return Pow(x,Real(1.0/gamma));
}

inline Real Bias(Real b, Real x)
{
  return Pow(x,Real(-Ln(b)/0.693147180559945));
}

inline Real Gain(Real g, Real x)
{
  if (x<0.5)
    return Bias(1.0-g,2.0*x)*0.5;
	else
    return 1.0-Bias(1.0-g,2.0-2.0*x)*0.5;
}

inline Vector CutColor(const Vector &v)
{
	Vector 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 Real Truncate(Real x)
{
	if (x>=0.0)
		return Floor(x);
	else
		return Ceil(x);
}

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

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

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

inline Real VectorAngle(const Vector &v1, const Vector &v2)
{
	Real l=Sqrt((v1*v1)*(v2*v2));
	if (l==0.0) return 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 Real VectorMin(const Vector &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 Real VectorMax(const Vector &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);						// calculate euler angles from Matrix
Vector VectorToHPB			(const Vector &p);						// calculate euler angles from vector, bank always 0.0
Matrix HPBToMatrix			(const Vector &hpb);					// 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);	// calculate optimal angles between two angle values
Vector PointLineDistance(const Vector &p0, const Vector &v, const Vector &p);
LVector ReflectRay			(LVector *v, Vector *n);

class MinMax
{
	private:
		Vector min,max;
		Bool   used;

	public:
		MinMax(void) { min=MAXREAL; max=MINREAL; used=FALSE; }
		inline MinMax(const Vector &v) { min=max=v; used=TRUE; }
		inline void Init(void) { min=MAXREAL; max=MINREAL; used=FALSE; } // reset min and max
		inline void AddPoint(const Vector &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 Bool   Content(void)	const { return used; }
		inline Vector GetMin (void) const { if (used) return min; else return 0.0; }
		inline Vector GetMax (void) const { if (used) return max; else return 0.0; }
		inline Vector GetMp  (void) const { if (used) return (min+max)*0.5; else return 0.0; } // middle between min and max
		inline Vector GetRad (void) const { if (used) return (max-min)*0.5; else return 0.0; } // half distance between min and max
		inline void GetMpRad(Vector *mp, Vector *rad) const { if (used) {*mp = (min+max)*0.5; *rad = max - *mp; } else *mp=*rad=0.0; } // half distance between min and max
};

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; }
};

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); }

	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); }

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

// shadow options for Illuminate routines
#define ILLUMINATE_SHADOW_OFF										0
#define ILLUMINATE_SHADOW_ON										1
#define ILLUMINATE_SHADOW_NOENVIRONMENT					2
#define ILLUMINATE_DISABLESHADOWMAP_CORRECTION	(1<<20)

struct IlluminanceSurfacePointData 
{
	Vector			p,bumpn,phongn,orign,ray_vector;
	Real				specular_exponent;
	Bool				receive_gi,receive_caustics,cosine_cutoff;
	LONG				calc_shadow,raybits,lhit;
							
	void*				local_mat;
	
	IlluminanceSurfacePointModel*	model;
	void*													customdata;
};

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

	public:

	// illumination functions
	void			CalcArea(RayLight *light, Bool nodiffuse, Bool nospecular, Real specular_exponent, const Vector &ray_vector, const Vector &p, const Vector &bumpn, const Vector &orign, LONG 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 Vector &p, const Vector &bumpn, const Vector &phongn, const Vector &orign, const Vector &rayv, Bool transparency, LONG global_id, LONG raybits) { return C4DOS.Sh->CalcShadow(this,l,p,bumpn,phongn,orign,rayv,transparency,global_id,raybits); }

	Bool	    IlluminateSurfacePoint(RayLight *rl, Vector *col, Vector *light_vector, const Vector &p, const Vector &bumpn, const Vector &phongn, const Vector &orign, const Vector &ray_vector, LONG calc_shadow, LONG global_id, LONG raybits, Bool cosine_cutoff) { return C4DOS.Sh->Illuminate(this,rl,col,light_vector,p,bumpn,phongn,orign,ray_vector,calc_shadow,global_id,raybits,cosine_cutoff,NULL); }
	Bool	    IlluminateAnyPoint    (RayLight *rl, Vector *col, Vector *light_vector, const Vector &p, LONG calc_shadow, LONG raybits) { return C4DOS.Sh->Illuminate(this,rl,col,light_vector,p,0.0,0.0,0.0,0.0,calc_shadow,0,raybits,FALSE,NULL); }

	void			IlluminanceSurfacePoint(IlluminanceSurfacePointData *f, Vector *diffuse, Vector *specular) { C4DOS.Sh->IlluminanceSurfacePoint(this,f,diffuse,specular); }
	Vector    IlluminanceAnyPoint(const Vector &p, LONG calc_shadow, LONG raybits) { return C4DOS.Sh->IlluminanceAnyPoint(this,p,calc_shadow,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); }
	RayObject *ID_to_Obj(LONG global_id, LONG *local_id) { return C4DOS.Sh->ID_to_Obj(this,global_id,local_id); }
	LONG	    Obj_to_ID(RayObject *op) { return C4DOS.Sh->Obj_to_ID(this,op); }
	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); }
	Vector	  GetNormal(RayObject *op, LONG local_id) { return C4DOS.Sh->GetNormal(this,op,local_id); }
	LONG			GetRayPolyState(RayObject *op, LONG local_id) { return C4DOS.Sh->GetRayPolyState(this,op,local_id); }
	Vector	  GetSmoothedNormal(LONG global_id, const Vector &p) { return C4DOS.Sh->GetSmoothedNormal(this,global_id,p); }
	Bool      GetRS(LONG global_id, const Vector &p, Real *r, Real *s) { return C4DOS.Sh->GetRS(this,global_id,p,r,s); }
	void      GetWeights(LONG global_id, const Vector &p, RayPolyWeight *wgt) { C4DOS.Sh->GetWeights(this,global_id,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); }
	Vector    ScreenToCamera(const Vector &p) { return C4DOS.Sh->ScreenToCamera(this,p); }
	Vector    CameraToScreen(const Vector &p) { return C4DOS.Sh->CameraToScreen(this,p); }
	Vector    CalcHardShadow(const Vector &p1, const Vector &p2, Bool transparency, LONG last_hit) { return C4DOS.Sh->CalcHardShadow(this,p1,p2,transparency,last_hit); }
	Vector		GetPointUVW(TexData *tdp, LONG global_id, const Vector &p) { return C4DOS.Sh->GetPointUVW(this,tdp,global_id,p); }
	Bool			ProjectPoint(TexData *tdp, LONG global_id, const Vector &p, const Vector &n, Vector *uv)	{ return C4DOS.Sh->ProjectPoint(this,tdp,global_id,p,n,uv); }
	void			StatusSetText(const String &str) { C4DOS.Sh->StatusSetText(this,&str); }
	void			StatusSetBar(Real percentage) { C4DOS.Sh->StatusSetBar(this,percentage); }
	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);
	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); }
	PluginVideoPost* GetVideoPost(LONG nth) { return C4DOS.Sh->FindVideoPost(this,nth,TRUE); }
	PluginVideoPost* FindVideoPost(LONG id) { return C4DOS.Sh->FindVideoPost(this,id,FALSE); }
	VPFragment	**GetFragments(LONG x, LONG y, LONG cnt, LONG flags) { return C4DOS.Sh->VPGetFragments(this,x,y,cnt,flags); }
	Bool			AddLensGlow(LensGlowStruct *lgs, Vector *lgs_pos, LONG lgs_cnt, Real intensity) { return C4DOS.Sh->AddLensGlow(this,lgs,lgs_pos,lgs_cnt,intensity); }
	Bool			SampleLensFX(VPBuffer *rgba, VPBuffer *fx, BaseThread *bt) { return C4DOS.Sh->SampleLensFX(this,rgba,fx,bt); }
	UWORD*		GetFragmentMask(void) { return C4DOS.Sh->GetFragmentMask(this); }
	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); }
	Bool			SetRayTolerance(Real tolerance) { return C4DOS.Sh->SetRayTolerance(this,tolerance); }

	Vector    TraceColor(Ray *ray, Real maxdist, LONG last_hit, SurfaceIntersection *si) { return C4DOS.Sh->TraceColor(this,ray,maxdist,last_hit,si); }
	Vector    TraceColorDirect(Ray *ray, Real maxdist, LONG raydepth, LONG raybits, LONG last_hit, Vector *oldray, SurfaceIntersection *si) { return C4DOS.Sh->TraceColorDirect(this,ray,maxdist,raydepth,raybits,last_hit,oldray,si); }
	Bool      TraceGeometry(Ray *ray, Real maxdist, LONG last_hit, SurfaceIntersection *si)  { return C4DOS.Sh->TraceGeometry(this,ray,maxdist,last_hit,si); }
	Bool      TraceGeometryEnhanced(Ray *ray, Real maxdist, LONG last_hit, LONG raydepth, LONG raybits, Vector *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); }

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

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

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

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

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

	// no longer use these routines
	void      LightCalcSpecialEx(RayLight *rl, Real exponent, Bool nodiff, Bool nospec, const Vector &rayv, Real cosc, const Vector &p, const Vector &bumpn, Vector &diffuse, Vector &specular);
	void			GetDUDVEx(TexData *tex, const Vector &p, const Vector &n, Vector *ddu, Vector *ddv) { C4DOS.Sh->GetDUDV_Ex(this,tex,p,n,ddu,ddv); }
	Bool	    IlluminateEx(RayLight *rl, Vector *color, Vector *light_vector, const Vector &p, const Vector &n, LONG calc_shadow, LONG last_hit) { return C4DOS.Sh->IlluminateEx(this,rl,color,light_vector,p,n,calc_shadow,last_hit); }
	void	    Illuminance2Ex(Vector *diffuse, Vector *specular, Real exponent, Vector *p, Vector *n, Vector *bumpn, Vector *rayv, LONG calc_shadow) { C4DOS.Sh->Illuminance2(this,diffuse,specular,exponent,p,n,bumpn,rayv,calc_shadow); }
	Vector    Illuminance3Ex(Vector *p, LONG calc_shadow) { return C4DOS.Sh->Illuminance3Ex(this,p,calc_shadow); }
	Vector    CalcShadow(RayLight *l, const Vector &p, const Vector &n, Bool transparency, LONG last_hit) { return C4DOS.Sh->CalcShadowEx(this,l,p,n,transparency,last_hit); }

	// only use those routines if you don't need to support SPD
	Vector    TraceColorEx(Ray *ray, Real maxdist, LONG last_hit, Vector *p, Vector *n, LONG *hit) { return C4DOS.Sh->TraceColorEx(this,ray,maxdist,last_hit,p,n,hit); }
	Vector    TraceColorDirectEx(Ray *ray, Real maxdist, LONG raydepth, LONG raybits, LONG last_hit, LVector *p, LVector *n, LONG *hit) { return C4DOS.Sh->TraceColorDirectEx(this,ray,maxdist,raydepth,raybits,last_hit,p,n,hit); }
	void      TraceGeometryEx(Ray *ray, Real maxdist, LONG last_hit, Vector *p, Vector *n, LONG *hit)  { C4DOS.Sh->TraceGeometryEx(this,ray,maxdist,last_hit,p,n,hit); }
	void  		GetSurfaceDataEx(SurfaceData *cd, Bool calc_illum, Bool calc_shadow, Bool calc_refl, Bool calc_trans, Ray *ray, const Vector &p, const Vector &n, LONG global_id) { C4DOS.Sh->GetSurfaceDataEx(this,cd,calc_illum,calc_shadow,calc_refl,calc_trans,ray,p,n,global_id); }

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

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

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

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

	public:
		void AddLine(Real *line, LONG y);
		void EvaluateLine(Bool display, LONG y, LONG xcnt, BaseBitmap *bmp, AlphaBitmap *alpha);
		LONG GetYRadius(void);
		void SetRange(LONG t_top, LONG t_bottom);

	static RayFilter *Alloc(LONG xres, LONG yres, LONG components, LONG left, LONG right, LONG type, Real softness, Bool dithering);
	static void Free(RayFilter *&filter);
};

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

	public:
		LONG GetInfo(LONG 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);
		void					UpdateScreen(void);
		VolumeData		*GetInitialVolumeData(LONG cpu);
		void*					GetPrivateData(void);
		Bool					SetRenderProperty(LONG id, const GeData &dat);
};

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_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
                                   // 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_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_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_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

  // return value
  BAKE_TEX_ERR_NO_DOC               = 3000, // no document
  BAKE_TEX_ERR_NO_MEM               = 3001, // no more memory available
  BAKE_TEX_ERR_NO_RENDER_DOC        = 3002, // no render document
  BAKE_TEX_ERR_NO_TEXTURE_TAG       = 3003, // textag is NULL or not in doc
  BAKE_TEX_ERR_NO_OBJECT            = 3004, // one of the tags is not assigned to an object or to another object
  BAKE_TEX_ERR_NO_UVW_TAG           = 3005, // UVW Tag is missing
  BAKE_TEX_ERR_TEXTURE_MISSING      = 3006, // no texture
	BAKE_TEX_ERR_WRONG_BITMAP         = 3007, // MultipassBitmap was used, but it has the wrong type or wrong resolution
	BAKE_TEX_ERR_USERBREAK            = 3008, // user break
	BAKE_TEX_ERR_NO_OPTIMAL_MAPPING		= 3009, // optimal mapping failed

	// states for BakeProgressInfo
	BAKE_STATE_PREPARE                = 10000,
	BAKE_STATE_GI_PREPASS             = 10001,
	BAKE_STATE_FILL_IMAGE             = 10002,
	BAKE_STATE_COMPLETE               = 10003,
	BAKE_STATE_INITIALIZE             = 10004,

	BAKE_RESIZE_NOTIFY                = 19999,

  BAKE_TEX_DUMMY
};

/* 
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 pojection 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 MODE_RGB, MODE_RGBA, MODE_RGBw, MODE_RGBAw, MODE_RGBf, MODE_RGBAf
MultipassBitmaps must be used if BAKE_TEX_AMBIENT_OCCLUSION is set
*/

struct BakeProgressInfo
{
	BakeProgressInfo() { ClearMem(this, sizeof(BakeProgressInfo)); version = 1; }
	LONG version;
	void* private_data;
	LONG state;
	void* data; // data is only used in case of a BAKE_RESIZE_NOTIFY message
	LONG time;
	Real r;
};

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);
};


LONG BakeTexture(BaseDocument* doc, const BaseContainer &data, BaseBitmap *bmp, BaseThread* th, BakeProgressHook* hook, BakeProgressInfo* info);
BaseDocument* InitBakeTexture(BaseDocument* doc, TextureTag* textag, UVWTag* texuvw, UVWTag* destuvw, const BaseContainer &bc, LONG* err = NULL, BaseThread* th = NULL);
BaseDocument* InitBakeTexture(BaseDocument* doc, TextureTag** textags, UVWTag** texuvws, UVWTag** destuvws, LONG cnt, const BaseContainer &bc, LONG* err = NULL, BaseThread* th = NULL);

#endif
