//////////////////////////////////////////////////////////////////////
//
//                             Pixie
//
// Copyright © 1999 - 2003, Okan Arikan
//
// Contact: okan@cs.berkeley.edu
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//
//  File				:	shaderFunctions.h
//  Classes				:	-
//  Description			:	Shader language specific buint in functions
//
////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// debug	"o=v"
#define	DEBUGVEXPR		debugFunction((float *) res);


DEFFUNC(DebugFloat		,"debug"		,"o=f", FUN1EXPR_PRE, DEBUGVEXPR, FUN1EXPR_UPDATE(1), NULL_EXPR, 0)
DEFLINKFUNC(DebugP		,"debug"		,"o=p",	0)
DEFLINKFUNC(DebugC		,"debug"		,"o=c",	0)
DEFLINKFUNC(DebugN		,"debug"		,"o=n",	0)
DEFFUNC(DebugVector		,"debug"		,"o=v", FUN1EXPR_PRE, DEBUGVEXPR, FUN1EXPR_UPDATE(3), NULL_EXPR, 0)



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// faceforward "v=vv"
#define	FACEFORWARDEXPR_PRE		const float	*Ng	=	varying[VARIABLE_NG];			\
								FUN3EXPR_PRE
								
#define	FACEFORWARDEXPR			if (dotvv(&op1->real,Ng) > 0) {						\
									if (dotvv(&op2->real,Ng) > 0)					\
										mulvf(&res->real,&op1->real,-1);			\
									else											\
										movvv(&res->real,&op1->real);				\
								} else {											\
									if (dotvv(&op2->real,Ng) > 0)					\
										movvv(&res->real,&op1->real);				\
									else											\
										mulvf(&res->real,&op1->real,-1);			\
								}


#define	FACEFORWARDEXPR_UPDATE	FUN3EXPR_UPDATE(3,3,3);								\
								Ng		+=	3;

DEFFUNC(FaceForward		,"faceforward"			,"v=vv"	,FACEFORWARDEXPR_PRE,FACEFORWARDEXPR,FACEFORWARDEXPR_UPDATE,NULL_EXPR,PARAMETER_NG)

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// faceforward "v=vvv"
#define	FACEFORWARD2EXPR		if (dotvv(&op1->real,&op3->real) > 0) {				\
									if (dotvv(&op2->real,&op3->real) > 0)			\
										mulvf(&res->real,&op1->real,-1);			\
									else											\
										movvv(&res->real,&op1->real);				\
								} else {											\
									if (dotvv(&op2->real,&op3->real) > 0)			\
										movvv(&res->real,&op1->real);				\
									else											\
										mulvf(&res->real,&op1->real,-1);			\
								}


DEFFUNC(FaceForward3		,"faceforward"		,"v=vvv",FUN4EXPR_PRE,FACEFORWARD2EXPR,FUN4EXPR_UPDATE(3,3,3,3),NULL_EXPR,0)




// The following macros are used to evaluate u and v derivatives using central differencing




		


									
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// du "f=f"
#ifndef INIT_SHADING
#define	DUFEXPR_PRE				FUN2EXPR_PRE																		\
								duFloat((float *) res,(float *) op);
#else
#undef	DUFEXPR_PRE
#define	DUFEXPR_PRE
#endif

DEFFUNC(Duf		,"Du"			,"f=f"	,DUFEXPR_PRE,NULL_EXPR,NULL_EXPR,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	DUVEXPR_PRE
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// du "v=v"
#ifndef INIT_SHADING
#define	DUVEXPR_PRE				FUN2EXPR_PRE																		\
								duVector((float *) res,(float *) op);

#else
#undef	DUVEXPR_PRE
#define	DUVEXPR_PRE
#endif

DEFLINKFUNC(Duv1	,"Du"		,"v=c",	PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)
DEFLINKFUNC(Duv2	,"Du"		,"v=p",	PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)
DEFLINKFUNC(Duv3	,"Du"		,"v=n",	PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)
DEFFUNC(Duv			,"Du"		,"v=v"	,DUVEXPR_PRE,NULL_EXPR,NULL_EXPR,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	DUVEXPR_PRE


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// dv "f=f"
#ifndef INIT_SHADING
#define	DVFEXPR_PRE				FUN2EXPR_PRE																	\
								dvFloat((float *) res,(float *) op);
#else
#undef	DVFEXPR_PRE
#define	DVFEXPR_PRE
#endif

DEFFUNC(Dvf		,"Dv"			,"f=f"	,DVFEXPR_PRE,NULL_EXPR,NULL_EXPR,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	DVFEXPR_PRE

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// dv "v=v"
#ifndef INIT_SHADING
#define	DVVEXPR_PRE				FUN2EXPR_PRE																	\
								dvVector((float *) res,(float *) op);
#else
#undef	DVVEXPR_PRE
#define	DVVEXPR_PRE	
#endif


DEFLINKFUNC(Dvv1	,"Dv"		,"v=c",	PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)
DEFLINKFUNC(Dvv2	,"Dv"		,"v=p",	PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)
DEFLINKFUNC(Dvv3	,"Dv"		,"v=n",	PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)
DEFFUNC(Dvv			,"Dv"		,"v=v"	,DVVEXPR_PRE,NULL_EXPR,NULL_EXPR,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	DVVEXPR_PRE

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// deriv "f=ff"
#ifndef INIT_SHADING
#define	DERIVFEXPR_PRE			FUN3EXPR_PRE																\
								float	*duTop		=	(float *) ralloc(numVertices*sizeof(float)*4);		\
								float	*duBottom	=	duTop + numVertices;								\
								float	*dvTop		=	duBottom + numVertices;								\
								float	*dvBottom	=	dvTop + numVertices;								\
								duFloat(duTop,		(float *) op1);											\
								duFloat(duBottom,	(float *) op2);											\
								dvFloat(dvTop,		(float *) op1);											\
								dvFloat(dvBottom,	(float *) op2);

#define	DERIVFEXPR				if (duBottom[0] != 0) {														\
									res[0].real	=	duTop[0] / duBottom[0];									\
								} else {																	\
									res[0].real	=	0;														\
								}																			\
																											\
								if (dvBottom[0] != 0) {														\
									res[0].real	+=	dvTop[0] / dvBottom[0];									\
								}



#define	DERIVFEXPR_UPDATE		res++;																		\
								duTop++;																	\
								duBottom++;																	\
								dvTop++;																	\
								dvBottom++;

#else

#define	DERIVFEXPR_PRE
#define	DERIVFEXPR
#define	DERIVFEXPR_UPDATE

#endif

DEFFUNC(Derivf		,"Deriv"			,"f=ff"	,DERIVFEXPR_PRE,DERIVFEXPR,DERIVFEXPR_UPDATE,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	DERIVFEXPR_PRE
#undef	DERIVFEXPR
#undef	DERIVFEXPR_UPDATE

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// deriv "v=vf"
#ifndef INIT_SHADING
#define	DERIVVEXPR_PRE			FUN3EXPR_PRE																\
								float	*duTop		=	(float *) ralloc(numVertices*sizeof(float)*8);		\
								float	*duBottom	=	duTop + numVertices*3;								\
								float	*dvTop		=	duBottom + numVertices;								\
								float	*dvBottom	=	dvTop + numVertices*3;								\
								duVector(duTop,		(float *) op1);											\
								duFloat(duBottom,	(float *) op2);											\
								dvVector(dvTop,		(float *) op1);											\
								dvFloat(dvBottom,	(float *) op2);

#define	DERIVVEXPR				if (duBottom[0] != 0) {														\
									res[0].real	=	duTop[0] / duBottom[0];									\
									res[1].real	=	duTop[1] / duBottom[0];									\
									res[2].real	=	duTop[2] / duBottom[0];									\
								} else {																	\
									res[0].real	=	0;														\
									res[1].real	=	0;														\
									res[2].real	=	0;														\
								}																			\
																											\
								if (dvBottom[0] != 0) {														\
									res[0].real	+=	dvTop[0] / dvBottom[0];									\
									res[1].real	+=	dvTop[1] / dvBottom[0];									\
									res[2].real	+=	dvTop[2] / dvBottom[0];									\
								}


#define	DERIVVEXPR_UPDATE		res			+=	3;															\
								duTop		+=	3;															\
								dvTop		+=	3;															\
								duBottom++;																	\
								dvBottom++;

#else
#define	DERIVVEXPR_PRE
#define	DERIVVEXPR
#define	DERIVVEXPR_UPDATE
#endif

DEFLINKFUNC(Derivv1		,"Deriv"		,"v=cf",	PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)
DEFLINKFUNC(Derivv2		,"Deriv"		,"v=pf",	PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)
DEFLINKFUNC(Derivv3		,"Deriv"		,"v=nf",	PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)
DEFFUNC(Derivv			,"Deriv"		,"v=vf"	,	DERIVVEXPR_PRE,DERIVVEXPR,DERIVVEXPR_UPDATE,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	DERIVVEXPR_PRE
#undef	DERIVVEXPR
#undef	DERIVVEXPR_UPDATE

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// area "f=p"
#ifndef INIT_SHADING
#define	AREAEXPR_PRE			FUN2EXPR_PRE																\
								float	*du		=	varying[VARIABLE_DU];									\
								float	*dv		=	varying[VARIABLE_DV];									\
								float	*dPdu	=	(float *) ralloc(numVertices*6*sizeof(float));			\
								float	*dPdv	=	dPdu + numVertices*3;									\
								vector	tmp;																\
								duVector(dPdu,(float *) op);												\
								dvVector(dPdv,(float *) op);
								

#define	AREAEXPR				mulvf(dPdu,du[0]);															\
								mulvf(dPdv,dv[0]);															\
								crossvv(tmp,dPdu,dPdv);														\
								res->real	=	lengthv(tmp);

#define	AREAEXPR_UPDATE			res++;																		\
								dPdu	+=	3;																\
								dPdv	+=	3;																\
								du++;																		\
								dv++;
#else
#define	AREAEXPR_PRE
#define	AREAEXPR
#define	AREAEXPR_UPDATE
#endif

DEFFUNC(Area		,"area"			,"f=p"	,AREAEXPR_PRE,AREAEXPR,AREAEXPR_UPDATE,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	AREAEXPR_PRE
#undef	AREAEXPR
#undef	AREAEXPR_UPDATE


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// calculatenormal "p=p"
#ifndef INIT_SHADING

#define	CALCULATENORMALEXPR_PRE		FUN2EXPR_PRE																\
									float	*dPdu	=	(float *) ralloc(numVertices*6*sizeof(float));			\
									float	*dPdv	=	dPdu + numVertices*3;									\
									float	mult	=	((currentShadingState->currentObject->attributes->flags & ATTRIBUTES_FLAGS_INSIDE) ? (float) -1 : (float) 1);	\
									duVector(dPdu,(float *) op);												\
									dvVector(dPdv,(float *) op);

#define	CALCULATENORMALEXPR			crossvv((float *) res,dPdu,dPdv);											\
									mulvf((float *) res,mult);

#define	CALCULATENORMALEXPR_UPDATE	res		+=	3;																\
									dPdu	+=	3;																\
									dPdv	+=	3;
#else
#define	CALCULATENORMALEXPR_PRE
#define	CALCULATENORMALEXPR
#define	CALCULATENORMALEXPR_UPDATE
#endif

DEFFUNC(CalculateNormal		,"calculatenormal"			,"p=p"	,CALCULATENORMALEXPR_PRE,CALCULATENORMALEXPR,CALCULATENORMALEXPR_UPDATE,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	CALCULATENORMALEXPR_PRE
#undef	CALCULATENORMALEXPR
#undef	CALCULATENORMALEXPR_UPDATE


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// noise	"f=f"
#define	NOISE1D1EXPR				res->real	=	FUNCTION(op->real);
#define	NOISE1D2EXPR				res->real	=	FUNCTION(op1->real,op2->real);
#define	NOISE1D3EXPR				res->real	=	FUNCTION(&op->real);
#define	NOISE1D4EXPR				res->real	=	FUNCTION(&op1->real,op2->real);

#define	NOISE3D1EXPR				FUNCTION(&res->real,op->real);
#define	NOISE3D2EXPR				FUNCTION(&res->real,op1->real,op2->real);
#define	NOISE3D3EXPR				FUNCTION(&res->real,&op->real);
#define	NOISE3D4EXPR				FUNCTION(&res->real,&op1->real,op2->real);

#define	FUNCTION	noiseFloat
DEFFUNC(Noise1D1			,"noise"		,"f=f"	,FUN2EXPR_PRE,NOISE1D1EXPR,FUN2EXPR_UPDATE(1,1),NULL_EXPR,0)
DEFFUNC(Noise1D2			,"noise"		,"f=ff"	,FUN3EXPR_PRE,NOISE1D2EXPR,FUN3EXPR_UPDATE(1,1,1),NULL_EXPR,0)
DEFFUNC(Noise1D3			,"noise"		,"f=p"	,FUN2EXPR_PRE,NOISE1D3EXPR,FUN2EXPR_UPDATE(1,3),NULL_EXPR,0)
DEFFUNC(Noise1D4			,"noise"		,"f=pf"	,FUN3EXPR_PRE,NOISE1D4EXPR,FUN3EXPR_UPDATE(1,3,1),NULL_EXPR,0)
#undef FUNCTION

#define	FUNCTION	noiseVector
DEFLINKFUNC(Noise1Dv1		,"noise"		,"c=f",	0)
DEFLINKFUNC(Noise1Dv2		,"noise"		,"p=f",	0)
DEFLINKFUNC(Noise1Dv3		,"noise"		,"n=f",	0)
DEFFUNC(Noise3D1			,"noise"		,"v=f"	,FUN2EXPR_PRE,NOISE3D1EXPR,FUN2EXPR_UPDATE(3,1),NULL_EXPR,0)
DEFLINKFUNC(Noise2Dv1		,"noise"		,"c=ff",	0)
DEFLINKFUNC(Noise2Dv2		,"noise"		,"p=ff",	0)
DEFLINKFUNC(Noise2Dv3		,"noise"		,"n=ff",	0)
DEFFUNC(Noise3D2			,"noise"		,"v=ff"	,FUN3EXPR_PRE,NOISE3D2EXPR,FUN3EXPR_UPDATE(3,1,1),NULL_EXPR,0)
DEFLINKFUNC(Noise3Dv1		,"noise"		,"c=p",	0)
DEFLINKFUNC(Noise3Dv2		,"noise"		,"p=p",	0)
DEFLINKFUNC(Noise3Dv3		,"noise"		,"n=p",	0)
DEFFUNC(Noise3D3			,"noise"		,"v=p"	,FUN2EXPR_PRE,NOISE3D3EXPR,FUN2EXPR_UPDATE(3,3),NULL_EXPR,0)
DEFLINKFUNC(Noise4Dv1		,"noise"		,"c=pf",	0)
DEFLINKFUNC(Noise4Dv2		,"noise"		,"p=pf",	0)
DEFLINKFUNC(Noise4Dv3		,"noise"		,"n=pf",	0)
DEFFUNC(Noise3D4			,"noise"		,"v=pf"	,FUN3EXPR_PRE,NOISE3D4EXPR,FUN3EXPR_UPDATE(3,3,1),NULL_EXPR,0)
#undef FUNCTION

#define	FUNCTION	cellNoiseFloat
DEFFUNC(CellNoise1D1			,"cellnoise"		,"f=f"	,FUN2EXPR_PRE,NOISE1D1EXPR,FUN2EXPR_UPDATE(1,1),NULL_EXPR,0)
DEFFUNC(CellNoise1D2			,"cellnoise"		,"f=ff"	,FUN3EXPR_PRE,NOISE1D2EXPR,FUN3EXPR_UPDATE(1,1,1),NULL_EXPR,0)
DEFFUNC(CellNoise1D3			,"cellnoise"		,"f=p"	,FUN2EXPR_PRE,NOISE1D3EXPR,FUN2EXPR_UPDATE(1,3),NULL_EXPR,0)
DEFFUNC(CellNoise1D4			,"cellnoise"		,"f=pf"	,FUN3EXPR_PRE,NOISE1D4EXPR,FUN3EXPR_UPDATE(1,3,1),NULL_EXPR,0)
#undef FUNCTION

#define	FUNCTION	cellNoiseVector
DEFLINKFUNC(CellNoise1Dv1		,"cellnoise"		,"c=f",	0)
DEFLINKFUNC(CellNoise1Dv2		,"cellnoise"		,"p=f",	0)
DEFLINKFUNC(CellNoise1Dv3		,"cellnoise"		,"n=f",	0)
DEFFUNC(CellNoise3D1			,"cellnoise"		,"v=f"	,FUN2EXPR_PRE,NOISE3D1EXPR,FUN2EXPR_UPDATE(3,1),NULL_EXPR,0)
DEFLINKFUNC(CellNoise2Dv1		,"cellnoise"		,"c=ff",	0)
DEFLINKFUNC(CellNoise2Dv2		,"cellnoise"		,"p=ff",	0)
DEFLINKFUNC(CellNoise2Dv3		,"cellnoise"		,"n=ff",	0)
DEFFUNC(CellNoise3D2			,"cellnoise"		,"v=ff"	,FUN3EXPR_PRE,NOISE3D2EXPR,FUN3EXPR_UPDATE(3,1,1),NULL_EXPR,0)
DEFLINKFUNC(CellNoise3Dv1		,"cellnoise"		,"c=p",	0)
DEFLINKFUNC(CellNoise3Dv2		,"cellnoise"		,"p=p",	0)
DEFLINKFUNC(CellNoise3Dv3		,"cellnoise"		,"n=p",	0)
DEFFUNC(CellNoise3D3			,"cellnoise"		,"v=p"	,FUN2EXPR_PRE,NOISE3D3EXPR,FUN2EXPR_UPDATE(3,3),NULL_EXPR,0)
DEFLINKFUNC(CellNoise4Dv1		,"cellnoise"		,"c=pf",	0)
DEFLINKFUNC(CellNoise4Dv2		,"cellnoise"		,"p=pf",	0)
DEFLINKFUNC(CellNoise4Dv3		,"cellnoise"		,"n=pf",	0)
DEFFUNC(CellNoise3D4			,"cellnoise"		,"v=pf"	,FUN3EXPR_PRE,NOISE3D4EXPR,FUN3EXPR_UPDATE(3,3,1),NULL_EXPR,0)
#undef FUNCTION


#define	PNOISE1D1EXPR				res->real	=	FUNCTION(op1->real,op2->real);
#define	PNOISE1D2EXPR				res->real	=	FUNCTION(op1->real,op2->real,op3->real,op4->real);
#define	PNOISE1D3EXPR				res->real	=	FUNCTION(&op1->real,&op2->real);
#define	PNOISE1D4EXPR				res->real	=	FUNCTION(&op1->real,op2->real,&op3->real,op4->real);

#define	PNOISE3D1EXPR				FUNCTION(&res->real,op1->real,op2->real);
#define	PNOISE3D2EXPR				FUNCTION(&res->real,op1->real,op2->real,op3->real,op4->real);
#define	PNOISE3D3EXPR				FUNCTION(&res->real,&op1->real,&op2->real);
#define	PNOISE3D4EXPR				FUNCTION(&res->real,&op1->real,op2->real,&op3->real,op4->real);

#define	FUNCTION	pnoiseFloat
DEFFUNC(PNoise1D1			,"pnoise"		,"f=ff"		,FUN3EXPR_PRE,PNOISE1D1EXPR,FUN3EXPR_UPDATE(1,1,1),NULL_EXPR,0)
DEFFUNC(PNoise1D2			,"pnoise"		,"f=ffff"	,FUN5EXPR_PRE,PNOISE1D2EXPR,FUN5EXPR_UPDATE(1,1,1,1,1),NULL_EXPR,0)
DEFFUNC(PNoise1D3			,"pnoise"		,"f=pp"		,FUN3EXPR_PRE,PNOISE1D3EXPR,FUN3EXPR_UPDATE(1,3,3),NULL_EXPR,0)
DEFFUNC(PNoise1D4			,"pnoise"		,"f=pfpf"	,FUN5EXPR_PRE,PNOISE1D4EXPR,FUN5EXPR_UPDATE(1,3,1,3,1),NULL_EXPR,0)
#undef FUNCTION

#define	FUNCTION	pnoiseVector
DEFLINKFUNC(PNoise1Dv1		,"pnoise"		,"c=ff",	0)
DEFLINKFUNC(PNoise1Dv2		,"pnoise"		,"p=ff",	0)
DEFLINKFUNC(PNoise1Dv3		,"pnoise"		,"n=ff",	0)
DEFFUNC(PNoise3D1			,"pnoise"		,"v=ff"	,	FUN3EXPR_PRE,PNOISE3D1EXPR,FUN3EXPR_UPDATE(3,1,1),NULL_EXPR,0)
DEFLINKFUNC(PNoise2Dv1		,"pnoise"		,"c=ffff",	0)
DEFLINKFUNC(PNoise2Dv2		,"pnoise"		,"p=ffff",	0)
DEFLINKFUNC(PNoise2Dv3		,"pnoise"		,"n=ffff",	0)
DEFFUNC(PNoise3D2			,"pnoise"		,"v=ffff",	FUN5EXPR_PRE,PNOISE3D2EXPR,FUN5EXPR_UPDATE(3,1,1,1,1),NULL_EXPR,0)
DEFLINKFUNC(PNoise3Dv1		,"pnoise"		,"c=pp",	0)
DEFLINKFUNC(PNoise3Dv2		,"pnoise"		,"p=pp",	0)
DEFLINKFUNC(PNoise3Dv3		,"pnoise"		,"n=pp",	0)
DEFFUNC(PNoise3D3			,"pnoise"		,"v=pp"	,	FUN3EXPR_PRE,PNOISE3D3EXPR,FUN3EXPR_UPDATE(3,3,3),NULL_EXPR,0)
DEFLINKFUNC(PNoise4Dv1		,"pnoise"		,"c=pfpf",	0)
DEFLINKFUNC(PNoise4Dv2		,"pnoise"		,"p=pfpf",	0)
DEFLINKFUNC(PNoise4Dv3		,"pnoise"		,"n=pfpf",	0)
DEFFUNC(PNoise3D4			,"pnoise"		,"v=pfpf",	FUN5EXPR_PRE,PNOISE3D4EXPR,FUN5EXPR_UPDATE(3,3,1,3,1),NULL_EXPR,0)
#undef FUNCTION

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ctransform "c=Sc"
#define	CTRANSFORMEXPR_PRE	matrix				*from,*to;											\
							ECoordinateSystem	cSystem;											\
							FUN3EXPR_PRE															\
							findCoordinateSystem(op1->string,from,to,cSystem);
							
#define	CTRANSFORMEXPR		convertColorTo(&res->real,&op2->real,cSystem);

DEFFUNC(CTransform		,"ctransform"			,"c=Sc"	,CTRANSFORMEXPR_PRE,CTRANSFORMEXPR,FUN3EXPR_UPDATE(3,0,3),NULL_EXPR,0)

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ctransform "c=SSc"
#define	CTRANSFORMSEXPR_PRE	matrix				*from,*to;											\
							vector				vtmp;												\
							ECoordinateSystem	cSystemFrom,cSystemTo;								\
							FUN4EXPR_PRE															\
							findCoordinateSystem(op1->string,from,to,cSystemFrom);					\
							findCoordinateSystem(op2->string,from,to,cSystemTo);

#define CTRANSFORMSEXPR		convertColorFrom(vtmp,&op3->real,cSystemFrom);							\
							convertColorTo(&res->real,vtmp,cSystemTo);


DEFFUNC(CTransforms		,"ctransform"			,"c=SSc"	,CTRANSFORMSEXPR_PRE,CTRANSFORMSEXPR,FUN4EXPR_UPDATE(3,0,0,3),NULL_EXPR,0)

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// transform "p=Sp
#define	TRANSFORM1EXPR_PRE	ECoordinateSystem	cSystem;											\
							matrix				*from,*to;											\
							FUN3EXPR_PRE;															\
							findCoordinateSystem(op1->string,from,to,cSystem);


#define	TRANSFORM1EXPR		mulmp(&res->real,to[0],&op2->real);


#define	TRANSFORM1EXPR_UPDATE	FUN3EXPR_UPDATE(3,0,3);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// transform "p=SSp"
#define	TRANSFORM2EXPR_PRE	ECoordinateSystem	cSystemFrom,cSystemTo;											\
							matrix				*from1,*to1,*from2,*to2;										\
							vector				vtmp;															\
							FUN4EXPR_PRE;																		\
							findCoordinateSystem(op1->string,from1,to1,cSystemFrom);							\
							findCoordinateSystem(op2->string,from2,to2,cSystemTo);

#define	TRANSFORM2EXPR		mulmp(vtmp,from1[0],&op3->real);													\
							mulmp(&res->real,to2[0],vtmp);

#define	TRANSFORM2EXPR_UPDATE	FUN4EXPR_UPDATE(3,0,0,3);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// transform "p=mp"
#define	TRANSFORM3EXPR		mulmp(&res->real,&op1->real,&op2->real);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// transform "p=Smp"
#define	TRANSFORM4EXPR_PRE	ECoordinateSystem	cSystem;											\
							matrix				*from,*to;											\
							vector				vtmp;												\
							FUN4EXPR_PRE;															\
							findCoordinateSystem(op1->string,from,to,cSystem);

#define	TRANSFORM4EXPR		mulmp(vtmp,from[0],&op3->real);											\
							mulmp(&res->real,&op2->real,vtmp);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// vtransform "p=Sp
#define	VTRANSFORM1EXPR_PRE	ECoordinateSystem	cSystem;											\
							matrix				*from,*to;											\
							FUN3EXPR_PRE;															\
							findCoordinateSystem(op1->string,from,to,cSystem);

#define	VTRANSFORM1EXPR		mulmv(&res->real,to[0],&op2->real);


#define	VTRANSFORM1EXPR_UPDATE	FUN3EXPR_UPDATE(3,0,3);


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ntransform "p=Sp
#define	NTRANSFORM1EXPR_PRE	ECoordinateSystem	cSystem;											\
							matrix				*from,*to;											\
							FUN3EXPR_PRE;															\
							findCoordinateSystem(op1->string,from,to,cSystem);						\

#define	NTRANSFORM1EXPR		mulmn(&res->real,from[0],&op2->real);

#define	NTRANSFORM1EXPR_UPDATE	FUN3EXPR_UPDATE(3,0,3);												\


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// vtransform "p=SSp"
#define VTRANSFORM2EXPR_PRE	ECoordinateSystem	cSystemFrom,cSystemTo;								\
							matrix				*from1,*to1,*from2,*to2;							\
							vector				vtmp;												\
							FUN4EXPR_PRE;															\
							findCoordinateSystem(op1->string,from1,to1,cSystemFrom);				\
							findCoordinateSystem(op2->string,from2,to2,cSystemTo);

#define	VTRANSFORM2EXPR		mulmv(vtmp,from1[0],&op3->real);										\
							mulmv(&res->real,to2[0],vtmp);

#define VTRANSFORM2EXPR_UPDATE	FUN4EXPR_UPDATE(3,0,0,3);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ntransform "p=SSp"
#define NTRANSFORM2EXPR_PRE	ECoordinateSystem	cSystemFrom,cSystemTo;								\
							matrix				*from1,*to1,*from2,*to2;							\
							vector				vtmp;												\
							FUN4EXPR_PRE;															\
							findCoordinateSystem(op1->string,from1,to1,cSystemFrom);				\
							findCoordinateSystem(op2->string,from2,to2,cSystemTo);					\

#define	NTRANSFORM2EXPR		mulmn(vtmp,to1[0],&op3->real);											\
							mulmn(&res->real,from2[0],vtmp);

#define NTRANSFORM2EXPR_UPDATE	FUN4EXPR_UPDATE(3,0,0,3);


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// vtransform "p=mp"
#define	VTRANSFORM3EXPR		mulmv(&res->real,&op1->real,&op2->real);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ntransform "p=mp"
#define	NTRANSFORM3EXPR		matrix	mtmp;							\
							invertm(mtmp,&op1->real);				\
							mulmn(&res->real,mtmp,&op2->real);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// vtransform "p=Smp"
#define	VTRANSFORM4EXPR_PRE	ECoordinateSystem	cSystem;												\
							matrix				*from,*to;												\
							vector				vtmp;													\
							FUN4EXPR_PRE;																\
							findCoordinateSystem(op1->string,from,to,cSystem);

#define	VTRANSFORM4EXPR		mulmv(vtmp,from[0],&op3->real);												\
							mulmv(&res->real,&op2->real,vtmp);

#define	VTRANSFORM4EXPR_UPDATE	FUN4EXPR_UPDATE(3,0,16,3);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ntransform "p=Smp"
#define	NTRANSFORM4EXPR_PRE	ECoordinateSystem	cSystem;												\
							matrix				*from,*to;												\
							matrix				mtmp;													\
							vector				vtmp;													\
							FUN4EXPR_PRE;																\
							findCoordinateSystem(op1->string,from,to,cSystem);

#define	NTRANSFORM4EXPR		invertm(mtmp,&op2->real);													\
							mulmn(vtmp,to[0],&op3->real);												\
							mulmn(&res->real,mtmp,vtmp);

#define	NTRANSFORM4EXPR_UPDATE	FUN4EXPR_UPDATE(3,0,16,3);


DEFFUNC(Transform1		,"transform"			,"p=Sp"		,TRANSFORM1EXPR_PRE,TRANSFORM1EXPR,TRANSFORM1EXPR_UPDATE,NULL_EXPR,0)
DEFFUNC(Transform2		,"transform"			,"p=SSp"	,TRANSFORM2EXPR_PRE,TRANSFORM2EXPR,TRANSFORM2EXPR_UPDATE,NULL_EXPR,0)
DEFFUNC(Transform3		,"transform"			,"p=mp"		,FUN3EXPR_PRE,TRANSFORM3EXPR,FUN3EXPR_UPDATE(3,16,3),NULL_EXPR,0)
DEFFUNC(Transform4		,"transform"			,"p=Smp"	,TRANSFORM4EXPR_PRE,TRANSFORM4EXPR,FUN4EXPR_UPDATE(3,1,16,3),NULL_EXPR,0)
DEFFUNC(VTransform1		,"vtransform"			,"v=Sv"		,VTRANSFORM1EXPR_PRE,VTRANSFORM1EXPR,VTRANSFORM1EXPR_UPDATE,NULL_EXPR,0)
DEFFUNC(VTransform2		,"vtransform"			,"v=SSv"	,VTRANSFORM2EXPR_PRE,VTRANSFORM2EXPR,VTRANSFORM2EXPR_UPDATE,NULL_EXPR,0)
DEFFUNC(VTransform3		,"vtransform"			,"v=mv"		,FUN3EXPR_PRE,VTRANSFORM3EXPR,FUN3EXPR_UPDATE(3,16,3),NULL_EXPR,0)
DEFFUNC(VTransform4		,"vtransform"			,"v=Smv"	,VTRANSFORM4EXPR_PRE,VTRANSFORM4EXPR,VTRANSFORM4EXPR_UPDATE,NULL_EXPR,0)
DEFFUNC(NTransform1		,"ntransform"			,"n=Sn"		,NTRANSFORM1EXPR_PRE,NTRANSFORM1EXPR,NTRANSFORM1EXPR_UPDATE,NULL_EXPR,0)
DEFFUNC(NTransform2		,"ntransform"			,"n=SSn"	,NTRANSFORM2EXPR_PRE,NTRANSFORM2EXPR,NTRANSFORM2EXPR_UPDATE,NULL_EXPR,0)
DEFFUNC(NTransform3		,"ntransform"			,"n=mn"		,FUN3EXPR_PRE,NTRANSFORM3EXPR,FUN3EXPR_UPDATE(3,16,3),NULL_EXPR,0)
DEFFUNC(NTransform4		,"ntransform"			,"n=Smn"	,NTRANSFORM4EXPR_PRE,NTRANSFORM4EXPR,NTRANSFORM4EXPR_UPDATE,NULL_EXPR,0)



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// depth "f=p"
#define DEPTHEXPR		res->real	=	(op[2].real - clipMin) / (clipMax - clipMin);

DEFFUNC(Depth		,"depth"			,"f=p"	,FUN2EXPR_PRE,DEPTHEXPR,FUN2EXPR_UPDATE(1,3),NULL_EXPR,0)

		
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ambient	"c="
#define	AMBIENTEXPR_PRE		int				vertexN	=	0;										\
							TCode			*res;												\
							operand(0,res);														\
							runAmbientLights();

#define AMBIENTEXPR			movvv(&res->real,alights[vertexN].Cl);

#define	AMBIENTEXPR_UPDATE	res	+=	3;	vertexN++;

DEFFUNC(Ambient			,"ambient"				,"c="		,AMBIENTEXPR_PRE,AMBIENTEXPR,AMBIENTEXPR_UPDATE,NULL_EXPR,0)

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// diffuse	"c=n"
#define	DIFFUSEEXPR_PRE		const float		*P,*N;												\
							float			*costheta	=	(float *) ralloc(numVertices*sizeof(float));	\
							int				vertexN		=	0;									\
							TCode			*res;												\
							const TCode		*op;												\
							int				i;													\
							for (i=0;i<numVertices;i++) costheta[i]	=	0;						\
							operand(0,res);														\
							operand(1,op);														\
							P	=	varying[VARIABLE_P];										\
							N	=	&op->real;													\
							runLights(P,N,costheta);

#define DIFFUSEEXPR			shaderDiffuse(res,op,PI/2,lights[vertexN]);
		

#define	DIFFUSEEXPR_UPDATE	res		+=	3;														\
							op		+=	3;														\
							vertexN++;

DEFFUNC(Diffuse				,"diffuse"				,"c=n"		,DIFFUSEEXPR_PRE, DIFFUSEEXPR, DIFFUSEEXPR_UPDATE, NULL_EXPR, PARAMETER_P)

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// diffuse	"c=pnf"
#define	DIFFUSE2EXPR_PRE	TCode			*res;												\
							const TCode		*op1,*op2,*op3;										\
							float			*costheta	=	(float *) ralloc(numVertices*sizeof(float));	\
							int				vertexN	=	0;										\
							int				i;													\
							const float		*P,*N;												\
							operand(0,res);														\
							operand(1,op1);														\
							operand(2,op2);														\
							operand(3,op3);														\
							for (i=0;i<numVertices;i++)	costheta[i]	=	(float) cos(op3[i].real);	\
							P		=	&op1->real;												\
							N		=	&op2->real;												\
							runLights(P,N,costheta);

#define DIFFUSE2EXPR		shaderDiffuse(res,op2,op3->real,lights[vertexN]);

#define	DIFFUSE2EXPR_UPDATE	res		+=	3;														\
							op2		+=	3;														\
							op3		+=	1;														\
							vertexN++;

DEFFUNC(Diffuse2			,"diffuse"				,"c=pnf"	,DIFFUSE2EXPR_PRE, DIFFUSE2EXPR, DIFFUSE2EXPR_UPDATE, NULL_EXPR, 0)






///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// specular	"c=nvf"
#define	SPECULAREXPR_PRE		const float		*P,*N;												\
								int				vertexN	=	0;										\
								TCode			*res;												\
								const TCode		*op1,*op2,*op3;										\
								float			*costheta	=	(float *) ralloc(numVertices*sizeof(float));	\
								int				i;													\
								operand(0,res);														\
								operand(1,op1);														\
								operand(2,op2);														\
								operand(3,op3);														\
								for (i=0;i<numVertices;i++)	costheta[i]	=	0;						\
								P		=	varying[VARIABLE_P];									\
								N		=	&op1->real;												\
								runLights(P,N,costheta);

#define SPECULAREXPR			shaderSpecular(res,op1,op2,op3->real,lights[vertexN]);

#define	SPECULAREXPR_UPDATE		res		+=	3;														\
								op1		+=	3;														\
								op2		+=	3;														\
								op3		+=	1;														\
								vertexN++;

DEFFUNC(Specular				,"specular"				,"c=nvf"		,SPECULAREXPR_PRE, SPECULAREXPR, SPECULAREXPR_UPDATE, NULL_EXPR, PARAMETER_P)



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// phong	"c=nvf"
#define	PHONGEXPR_PRE			const float		*P,*N;												\
								int				vertexN	=	0;										\
								TCode			*res;												\
								const TCode		*op1,*op2,*op3;										\
								float			*costheta	=	(float *) ralloc(numVertices*sizeof(float));	\
								int				i;													\
								operand(0,res);														\
								operand(1,op1);														\
								operand(2,op2);														\
								operand(3,op3);														\
								for (i=0;i<numVertices;i++)	costheta[i]	=	0;						\
								P		=	varying[VARIABLE_P];									\
								N		=	&op1->real;												\
								runLights(P,N,costheta);

#define PHONGEXPR				shaderPhong(res,op1,op2,op3->real,lights[vertexN]);

#define	PHONGEXPR_UPDATE		res		+=	3;														\
								op1		+=	3;														\
								op2		+=	3;														\
								op3		+=	1;														\
								vertexN++;

DEFFUNC(Phong				,"phong"				,"c=nvf"		,PHONGEXPR_PRE, PHONGEXPR, PHONGEXPR_UPDATE, NULL_EXPR, PARAMETER_P)

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// specularBRDF	"c=vnvf"
#define	SPECULARBRDFEXPR_PRE	TCode			*res;												\
								const TCode		*op1,*op2,*op3,*op4;								\
								operand(0,res);														\
								operand(1,op1);														\
								operand(2,op2);														\
								operand(3,op3);														\
								operand(4,op4);

#define SPECULARBRDFEXPR		specularBRDF(res,op1,op2,op3,op4->real);


#define	SPECULARBRDFEXPR_UPDATE	res		+=	3;														\
								op1		+=	3;														\
								op2		+=	3;														\
								op3		+=	3;														\
								op4		+=	1;



DEFFUNC(SpecularBRDF			,"specularbrdf"				,"c=vnvf"		,SPECULARBRDFEXPR_PRE,SPECULARBRDFEXPR,SPECULARBRDFEXPR_UPDATE,NULL_EXPR,0)





#ifndef INIT_SHADING
#define	PARAMETEREXPR			res->real	=	(float) FUNCTION(&op2->real,op1->string);
#define	PARAMETERSEXPR			res->real	=	(float) FUNCTION(&op2->string,op1->string);
#else
#undef	PARAMETEREXPR
#undef	PARAMETERSEXPR
#define	PARAMETEREXPR
#define	PARAMETERSEXPR
#endif

#define	FUNCTION	displacementParameter
DEFLINKFUNC(Displacement2			,"displacement"				,"f=SC",	0)
DEFLINKFUNC(Displacement3			,"displacement"				,"f=SN",	0)
DEFLINKFUNC(Displacement4			,"displacement"				,"f=SP",	0)
DEFFUNC(DisplacementV				,"displacement"				,"f=SV"		,FUN3OUTEXPR_PRE,PARAMETEREXPR,FUN3EXPR_UPDATE(1,0,0),NULL_EXPR,0)
DEFFUNC(Displacement				,"displacement"				,"f=SF"		,FUN3OUTEXPR_PRE,PARAMETEREXPR,FUN3EXPR_UPDATE(1,0,0),NULL_EXPR,0)
DEFFUNC(DisplacementS				,"displacement"				,"f=SS"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,0),NULL_EXPR,0)
DEFFUNC(DisplacementM				,"displacement"				,"f=SM"		,FUN3OUTEXPR_PRE,PARAMETEREXPR,FUN3EXPR_UPDATE(1,0,0),NULL_EXPR,0)
#undef FUNCTION

#define	FUNCTION	surfaceParameter
DEFLINKFUNC(Surface2			,"surface"				,"f=SC",	0)
DEFLINKFUNC(Surface3			,"surface"				,"f=SN",	0)
DEFLINKFUNC(Surface4			,"surface"				,"f=SP",	0)
DEFFUNC(SurfaceV				,"surface"				,"f=SV"		,FUN3OUTEXPR_PRE,PARAMETEREXPR,FUN3EXPR_UPDATE(1,0,0),NULL_EXPR,0)
DEFFUNC(Surface					,"surface"				,"f=SF"		,FUN3OUTEXPR_PRE,PARAMETEREXPR,FUN3EXPR_UPDATE(1,0,0),NULL_EXPR,0)
DEFFUNC(SurfaceS				,"surface"				,"f=SS"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,0),NULL_EXPR,0)
DEFFUNC(SurfaceM				,"surface"				,"f=SM"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,0),NULL_EXPR,0)
#undef FUNCTION


#define	LIGHTPARAMETEREXPR			res->real	=	(float) currentLights[numVertices-currentVertex]->instance->getParameter(op1->string,&op2->real);
#define	LIGHTPARAMETERSEXPR			res->real	=	(float) currentLights[numVertices-currentVertex]->instance->getParameter(op1->string,&op2->string);

#define	FUNCTION	lightsourceParameter
DEFLINKFUNC(Lightsource2			,"lightsource"				,"f=SC",	0)
DEFLINKFUNC(Lightsource3			,"lightsource"				,"f=SN",	0)
DEFLINKFUNC(Lightsource4			,"lightsource"				,"f=SP",	0)
DEFFUNC(LightsourceV				,"lightsource"				,"f=SV"		,FUN3OUTEXPR_PRE,LIGHTPARAMETEREXPR,FUN3EXPR_UPDATE(1,0,3),NULL_EXPR,0)
DEFFUNC(Lightsource					,"lightsource"				,"f=SF"		,FUN3OUTEXPR_PRE,LIGHTPARAMETEREXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(LightsourceS				,"lightsource"				,"f=SS"		,FUN3OUTEXPR_PRE,LIGHTPARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(LightsourceM				,"lightsource"				,"f=SM"		,FUN3OUTEXPR_PRE,LIGHTPARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,16),NULL_EXPR,0)
#undef FUNCTION

#define	FUNCTION	atmosphereParameter
DEFLINKFUNC(Atmosphere2			,"atmosphere"				,"f=SC",	0)
DEFLINKFUNC(Atmosphere3			,"atmosphere"				,"f=SN",	0)
DEFLINKFUNC(Atmosphere4			,"atmosphere"				,"f=SP",	0)
DEFFUNC(AtmosphereV				,"atmosphere"				,"f=SV"		,FUN3OUTEXPR_PRE,PARAMETEREXPR,FUN3EXPR_UPDATE(1,0,3),NULL_EXPR,0)
DEFFUNC(Atmosphere				,"atmosphere"				,"f=SF"		,FUN3OUTEXPR_PRE,PARAMETEREXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(AtmosphereS				,"atmosphere"				,"f=SS"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(AtmosphereM				,"atmosphere"				,"f=SM"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,16),NULL_EXPR,0)
#undef FUNCTION

#define	FUNCTION	incidentParameter
DEFLINKFUNC(Incident2			,"incident"				,"f=SC",	0)
DEFLINKFUNC(Incident3			,"incident"				,"f=SN",	0)
DEFLINKFUNC(Incident4			,"incident"				,"f=SP",	0)
DEFFUNC(IncidentV				,"incident"				,"f=SV"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,3),NULL_EXPR,0)
DEFFUNC(Incident				,"incident"				,"f=SF"		,FUN3OUTEXPR_PRE,PARAMETEREXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(IncidentS				,"incident"				,"f=SS"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(IncidentM				,"incident"				,"f=SM"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,16),NULL_EXPR,0)

#undef FUNCTION

#define	FUNCTION	oppositeParameter
DEFLINKFUNC(Opposite2			,"opposite"				,"f=SC",	0)
DEFLINKFUNC(Opposite3			,"opposite"				,"f=SN",	0)
DEFLINKFUNC(Opposite4			,"opposite"				,"f=SP",	0)
DEFFUNC(OppositeV				,"opposite"				,"f=SV"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,3),NULL_EXPR,0)
DEFFUNC(Opposite				,"opposite"				,"f=SF"		,FUN3OUTEXPR_PRE,PARAMETEREXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(OppositeS				,"opposite"				,"f=SS"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(OppositeM				,"opposite"				,"f=SM"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,16),NULL_EXPR,0)
#undef FUNCTION

#define	FUNCTION	attributes
DEFLINKFUNC(Attributes2			,"attributes"				,"f=SC",	0)
DEFLINKFUNC(Attributes3			,"attributes"				,"f=SN",	0)
DEFLINKFUNC(Attributes4			,"attributes"				,"f=SP",	0)
DEFFUNC(AttributesV				,"attributes"				,"f=SV"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,3),NULL_EXPR,0)
DEFFUNC(Attributes				,"attributes"				,"f=SF"		,FUN3OUTEXPR_PRE,PARAMETEREXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(AttributesS				,"attributes"				,"f=SS"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(AttributesM				,"attributes"				,"f=SM"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,16),NULL_EXPR,0)
#undef FUNCTION

#define	FUNCTION	options
DEFLINKFUNC(Options2			,"options"				,"f=SC",	0)
DEFLINKFUNC(Options3			,"options"				,"f=SN",	0)
DEFLINKFUNC(Options4			,"options"				,"f=SP",	0)
DEFFUNC(OptionsV				,"options"				,"f=SV"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,3),NULL_EXPR,0)
DEFFUNC(Options					,"options"				,"f=SF"		,FUN3OUTEXPR_PRE,PARAMETEREXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(OptionsS				,"options"				,"f=SS"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(OptionsM				,"options"				,"f=SM"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,16),NULL_EXPR,0)
#undef FUNCTION

#define	FUNCTION	rendererInfo
DEFLINKFUNC(Rendererinfo2			,"rendererinfo"				,"f=SC",	0)
DEFLINKFUNC(Rendererinfo3			,"rendererinfo"				,"f=SN",	0)
DEFLINKFUNC(Rendererinfo4			,"rendererinfo"				,"f=SP",	0)
DEFFUNC(RendererinfoV				,"rendererinfo"				,"f=SV"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,3),NULL_EXPR,0)
DEFFUNC(Rendererinfo				,"rendererinfo"				,"f=SF"		,FUN3OUTEXPR_PRE,PARAMETEREXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(RendererinfoS				,"rendererinfo"				,"f=SS"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,1),NULL_EXPR,0)
DEFFUNC(RendererinfoM				,"rendererinfo"				,"f=SM"		,FUN3OUTEXPR_PRE,PARAMETERSEXPR,FUN3EXPR_UPDATE(1,0,16),NULL_EXPR,0)
#undef FUNCTION

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// shadername	"s="
#define SHADERNAMEEXPR		res->string	=	(char *) currentShader->name;

DEFFUNC(ShaderName				,"shadername"					,"s="		,FUN1EXPR_PRE,SHADERNAMEEXPR,FUN1EXPR_UPDATE(1),NULL_EXPR,0)

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// shadername	"s=s"
#ifndef INIT_SHADING
#define SHADERNAMESEXPR		res->string	=	(char *) shaderName(op->string);
#else
#undef SHADERNAMESEXPR
#define SHADERNAMESEXPR
#endif

DEFFUNC(ShaderNames				,"shadername"					,"s=s"		,FUN2EXPR_PRE,SHADERNAMESEXPR,FUN2EXPR_UPDATE(1,1),NULL_EXPR,0)











///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//	Texture - Environment - Shadow mapping macros
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This macro is used to decode the texture parameter list
#define	TEXTUREPARAMETERS(start,num)																			\
								lookup					=	new CTextureLookup;									\
								parameterlist			=	lookup;												\
								dirty();																		\
								lookup->filter			=	RiGaussianFilter;									\
								lookup->blur			=	0;													\
								lookup->swidth			=	1;													\
								lookup->twidth			=	1;													\
								lookup->numSamples		=	1;													\
								lookup->channel			=	0;													\
								lookup->fill			=	0;													\
								lookup->shadowBias		=	currentShadingState->currentObject->attributes->shadowBias;	\
								lookup->maxDist			=	C_INFINITY;											\
								lookup->coneAngle		=	0;													\
								lookup->label			=	NULL;												\
								lookup->lookupFloat		=	TRUE;												\
								lookup->texture			=	NULL;												\
								lookup->environment		=	NULL;												\
								{																				\
									int		i;																	\
									TCode	*param,*val;														\
																												\
									for (i=0;i<num;i++) {														\
										operand(i*2+start,param);												\
										operand(i*2+start+1,val);												\
																												\
										if (strcmp(param->string,"filter") == 0) {								\
											lookup->filter	=	currentRenderer->getFilter(val->string);		\
										} else if (strcmp(param->string,"blur") == 0) {							\
											lookup->blur		=	val->real;									\
											lookup->coneAngle	=	(float) (PI*val->real);						\
										} else if (strcmp(param->string,"swidth") == 0) {						\
											lookup->swidth		=	val->real;									\
										} else if (strcmp(param->string,"fill") == 0) {							\
											lookup->fill			=	val->real;								\
										} else if (strcmp(param->string,"twidth") == 0) {						\
											lookup->twidth		=	val->real;									\
										} else if (strcmp(param->string,"samples") == 0) {						\
											lookup->numSamples	=	(int) val->real;							\
										} else if (strcmp(param->string,"bias") == 0) {							\
											lookup->shadowBias	=	val->real;									\
										} else if (strcmp(param->string,"maxdist") == 0) {						\
											lookup->maxDist		=	val->real;									\
										} else if (strcmp(param->string,"samplecone") == 0) {					\
											lookup->coneAngle	=	val->real;									\
										} else if (strcmp(param->string,"label") == 0) {						\
											lookup->label		=	val->string;								\
										}																		\
									}																			\
								}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// texture	"f=SFff"
#ifndef INIT_SHADING
#define	TEXTUREFEXPR_PRE		TCode			*res;															\
								const TCode		*op3,*op4;														\
								CTextureLookup	*lookup;														\
								if ((lookup = (CTextureLookup *) parameterlist) == NULL) {						\
									int			numArguments;													\
									TCode		*op1,*op2;														\
									argumentcount(numArguments);												\
									TEXTUREPARAMETERS(5,(numArguments-5) >> 1);									\
									operand(1,op1);																\
									operand(2,op2);																\
									lookup->texture				=	getTexture(op1->string);					\
									lookup->channel				=	(int) op2->real;							\
									lookup->lookupFloat			=	TRUE;										\
								}																				\
								operand(0,res);																	\
								operand(3,op3);																	\
								operand(4,op4);																	\
								int				i;																\
								float			*dsdu		=	(float *) ralloc(numVertices*4*sizeof(float));	\
								float			*dsdv		=	dsdu + numVertices;								\
								float			*dtdu		=	dsdv + numVertices;								\
								float			*dtdv		=	dtdu + numVertices;								\
								const float		*s			=	(const float *) op3;							\
								const float		*t			=	(const float *) op4;							\
								float			cs[4],ct[4];													\
								vector			color;															\
								const	float	swidth		=	lookup->swidth;									\
								const	float	twidth		=	lookup->twidth;									\
								CTexture		*tex		=	lookup->texture;								\
								const float		*du			=	varying[VARIABLE_DU];							\
								const float		*dv			=	varying[VARIABLE_DV];							\
																												\
								duFloat(dsdu,s);																\
								duFloat(dtdu,t);																\
								dvFloat(dsdv,s);																\
								dvFloat(dtdv,t);																\
																												\
								for (i=0;i<numVertices;i++) {													\
									dsdu[i]		*=	swidth*du[i];												\
									dsdv[i]		*=	swidth*dv[i];												\
									dtdu[i]		*=	twidth*du[i];												\
									dtdv[i]		*=	twidth*dv[i];												\
								}																				\
																												\
								i	=	0;

#define	TEXTUREFEXPR			cs[0]		=	s[i];															\
								cs[1]		=	s[i] + dsdu[i];													\
								cs[2]		=	s[i] + dsdv[i];													\
								cs[3]		=	s[i] + dsdu[i] + dsdv[i];										\
								ct[0]		=	t[i];															\
								ct[1]		=	t[i] + dtdu[i];													\
								ct[2]		=	t[i] + dtdv[i];													\
								ct[3]		=	t[i] + dtdu[i] + dtdv[i];										\
								tex->lookup4(color,cs,ct,lookup);												\
								res[i].real	=	color[0];

#define	TEXTUREFEXPR_UPDATE		i++;
#else
#define	TEXTUREFEXPR_PRE
#define	TEXTUREFEXPR
#define	TEXTUREFEXPR_UPDATE
#endif

DEFFUNC(TextureFloat			,"texture"					,"f=SFff!"		,TEXTUREFEXPR_PRE,TEXTUREFEXPR,TEXTUREFEXPR_UPDATE,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	TEXTUREFEXPR_PRE
#undef	TEXTUREFEXPR
#undef	TEXTUREFEXPR_UPDATE





///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// texture	"c=SFff"
#ifndef INIT_SHADING
#define	TEXTURECEXPR_PRE		TCode			*res;															\
								const TCode		*op3,*op4;														\
								CTextureLookup	*lookup;														\
								if ((lookup = (CTextureLookup *) parameterlist) == NULL) {						\
									int			numArguments;													\
									TCode		*op1,*op2;														\
									argumentcount(numArguments);												\
									TEXTUREPARAMETERS(5,(numArguments-5) >> 1);									\
									operand(1,op1);																\
									operand(2,op2);																\
									lookup->texture				=	getTexture(op1->string);					\
									lookup->channel				=	(int) op2->real;							\
									lookup->lookupFloat			=	FALSE;										\
								}																				\
								operand(0,res);																	\
								operand(3,op3);																	\
								operand(4,op4);																	\
								int				i;																\
								float			*dsdu		=	(float *) ralloc(numVertices*4*sizeof(float));	\
								float			*dsdv		=	dsdu + numVertices;								\
								float			*dtdu		=	dsdv + numVertices;								\
								float			*dtdv		=	dtdu + numVertices;								\
								const float		*s			=	(const float *) op3;							\
								const float		*t			=	(const float *) op4;							\
								float			cs[4],ct[4];													\
								const	float	swidth		=	lookup->swidth;									\
								const	float	twidth		=	lookup->twidth;									\
								CTexture		*tex		=	lookup->texture;								\
								const float		*du			=	varying[VARIABLE_DU];							\
								const float		*dv			=	varying[VARIABLE_DV];							\
																												\
								duFloat(dsdu,s);																\
								duFloat(dtdu,t);																\
								dvFloat(dsdv,s);																\
								dvFloat(dtdv,t);																\
																												\
								for (i=0;i<numVertices;i++) {													\
									dsdu[i]		*=	swidth*du[i];												\
									dsdv[i]		*=	swidth*dv[i];												\
									dtdu[i]		*=	twidth*du[i];												\
									dtdv[i]		*=	twidth*dv[i];												\
								}																				\
																												\
								i	=	0;

#define	TEXTURECEXPR			cs[0]		=	s[i];															\
								cs[1]		=	s[i] + dsdu[i];													\
								cs[2]		=	s[i] + dsdv[i];													\
								cs[3]		=	s[i] + dsdu[i] + dsdv[i];										\
								ct[0]		=	t[i];															\
								ct[1]		=	t[i] + dtdu[i];													\
								ct[2]		=	t[i] + dtdv[i];													\
								ct[3]		=	t[i] + dtdu[i] + dtdv[i];										\
								tex->lookup4((float *) res,cs,ct,lookup);

#define	TEXTURECEXPR_UPDATE		i++;	res	+=	3;
#else
#define	TEXTURECEXPR_PRE
#define	TEXTURECEXPR
#define	TEXTURECEXPR_UPDATE
#endif

DEFFUNC(TextureColor			,"texture"					,"c=SFff!"		,TEXTURECEXPR_PRE,TEXTURECEXPR,TEXTURECEXPR_UPDATE,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	TEXTURECEXPR_PRE
#undef	TEXTURECEXPR
#undef	TEXTURECEXPR_UPDATE


















///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// texture	"f=SFffffffff"
#ifndef INIT_SHADING
#define	TEXTUREFFULLEXPR_PRE	TCode			*res;															\
								const TCode		*op3,*op4,*op5,*op6,*op7,*op8,*op9,*op10;						\
								CTextureLookup	*lookup;														\
								float			cs[4],ct[4];													\
								vector			tmp;															\
								if ((lookup = (CTextureLookup *) parameterlist) == NULL) {						\
									int			numArguments;													\
									TCode		*op1,*op2;														\
									argumentcount(numArguments);												\
									TEXTUREPARAMETERS(11,(numArguments-11) >> 1);								\
									operand(1,op1);																\
									operand(2,op2);																\
									lookup->texture				=	getTexture(op1->string);					\
									lookup->channel				=	(int) op2->real;							\
									lookup->lookupFloat			=	TRUE;										\
								}																				\
								CTexture		*tex		=	lookup->texture;								\
								operand(0,res);																	\
								operand(3,op3);																	\
								operand(4,op4);																	\
								operand(5,op5);																	\
								operand(6,op6);																	\
								operand(7,op7);																	\
								operand(8,op8);																	\
								operand(9,op9);																	\
								operand(10,op10);

#define	TEXTUREFFULLEXPR		cs[0]		=	op3->real;														\
								cs[1]		=	op5->real;														\
								cs[2]		=	op7->real;														\
								cs[3]		=	op9->real;														\
								ct[0]		=	op4->real;														\
								ct[1]		=	op6->real;														\
								ct[2]		=	op8->real;														\
								ct[3]		=	op10->real;														\
								tex->lookup4(tmp,cs,ct,lookup);													\
								res->real	=	tmp[0];

#define	TEXTUREFFULLEXPR_UPDATE	res++;																			\
								op3++;																			\
								op4++;																			\
								op5++;																			\
								op6++;																			\
								op7++;																			\
								op8++;																			\
								op9++;																			\
								op10++;																			\


#else
#define	TEXTUREFFULLEXPR_PRE
#define	TEXTUREFFULLEXPR
#define	TEXTUREFFULLEXPR_UPDATE
#endif

DEFFUNC(TextureFloatFull			,"texture"				,"f=SFffffffff!"		,TEXTUREFFULLEXPR_PRE,TEXTUREFFULLEXPR,TEXTUREFFULLEXPR_UPDATE,NULL_EXPR,0)

#undef	TEXTUREFFULLEXPR_PRE
#undef	TEXTUREFFULLEXPR
#undef	TEXTUREFFULLEXPR_UPDATE






///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// texture	"c=SFffffffff"
#ifndef INIT_SHADING
#define	TEXTURECFULLEXPR_PRE	TCode			*res;															\
								const TCode		*op3,*op4,*op5,*op6,*op7,*op8,*op9,*op10;						\
								CTextureLookup	*lookup;														\
								float			cs[4],ct[4];													\
								if ((lookup = (CTextureLookup *) parameterlist) == NULL) {						\
									int			numArguments;													\
									TCode		*op1,*op2;														\
									argumentcount(numArguments);												\
									TEXTUREPARAMETERS(11,(numArguments-11) >> 1);								\
									operand(1,op1);																\
									operand(2,op2);																\
									lookup->texture				=	getTexture(op1->string);					\
									lookup->channel				=	(int) op2->real;							\
									lookup->lookupFloat			=	FALSE;										\
								}																				\
								CTexture		*tex		=	lookup->texture;								\
								operand(0,res);																	\
								operand(3,op3);																	\
								operand(4,op4);																	\
								operand(5,op5);																	\
								operand(6,op6);																	\
								operand(7,op7);																	\
								operand(8,op8);																	\
								operand(9,op9);																	\
								operand(10,op10);

#define	TEXTURECFULLEXPR		cs[0]		=	op3->real;														\
								cs[1]		=	op5->real;														\
								cs[2]		=	op7->real;														\
								cs[3]		=	op9->real;														\
								ct[0]		=	op4->real;														\
								ct[1]		=	op6->real;														\
								ct[2]		=	op8->real;														\
								ct[3]		=	op10->real;														\
								tex->lookup4((float *) res,cs,ct,lookup);

#define	TEXTURECFULLEXPR_UPDATE	res	+=	3;																		\
								op3++;																			\
								op4++;																			\
								op5++;																			\
								op6++;																			\
								op7++;																			\
								op8++;																			\
								op9++;																			\
								op10++;																			\


#else
#define	TEXTURECFULLEXPR_PRE
#define	TEXTURECFULLEXPR
#define	TEXTURECFULLEXPR_UPDATE
#endif

DEFFUNC(TextureColorFull			,"texture"				,"c=SFffffffff!"		,TEXTURECFULLEXPR_PRE,TEXTURECFULLEXPR,TEXTURECFULLEXPR_UPDATE,NULL_EXPR,0)

#undef	TEXTURECFULLEXPR_PRE
#undef	TEXTURECFULLEXPR
#undef	TEXTURECFULLEXPR_UPDATE
















///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//	Environment / Shadow mapping macros
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// environment	"f=SFv"
#ifndef INIT_SHADING
#define	ENVIRONMENTFEXPR_PRE	CTextureLookup	*lookup;															\
								TCode			*res;																\
								const TCode		*op3;																\
								int				i;																	\
								if ((lookup = (CTextureLookup *) parameterlist) == NULL) {							\
									TCode			*op2,*op1;														\
									int				numArguments;													\
									argumentcount(numArguments);													\
									TEXTUREPARAMETERS(4,(numArguments-4) >> 1);										\
									operand(1,op1);																	\
									operand(2,op2);																	\
									lookup->channel				=	(int) op2->real;								\
									lookup->lookupFloat			=	TRUE;											\
									if ((strcmp(op1->string,"raytrace")==0) || (strcmp(op1->string,"reflection") == 0)) {		\
										lookup->environment		=	NULL;											\
									} else {																		\
										lookup->environment		=	getEnvironment(op1->string);					\
									}																				\
								}																					\
								if (lookup->environment == NULL) {													\
									float			*color;															\
									const int		numRealVertices = currentShadingState->numRealVertices;			\
																													\
									operand(0,res);																	\
									operand(3,op3);																	\
																													\
									color						=	(float *) ralloc(numRealVertices*3*sizeof(float));	\
									traceReflection(color,varying[VARIABLE_P],(float *) op3,numRealVertices,tags,lookup);	\
																													\
									for (i=numRealVertices;i>0;i--,tags++,res++,color+=3) {							\
										if (*tags == 0) {															\
											res->real	=	(color[0] + color[1] + color[2]) / (float) 3;			\
										}																			\
									}																				\
								} else {																			\
									const float		*D;																\
									vector			color;															\
									CEnvironment	*tex;															\
									float			*dDdu		=	(float *) ralloc(numVertices*6*sizeof(float));	\
									float			*dDdv		=	dDdu + numVertices*3;							\
									const float		*du			=	varying[VARIABLE_DU];							\
									const float		*dv			=	varying[VARIABLE_DV];							\
									operand(0,res);																	\
									operand(3,op3);																	\
									D		=	(const float *) op3;												\
									tex		=	lookup->environment;												\
																													\
									duVector(dDdu,D);																\
									dvVector(dDdv,D);																\
																													\
									for (i=currentShadingState->numRealVertices;i>0;i--,tags++) {					\
										if (*tags == 0) {															\
											vector	D0,D1,D2,D3;													\
																													\
											D0[0]	=	D[0];														\
											D0[1]	=	D[1];														\
											D0[2]	=	D[2];														\
											D1[0]	=	D[0] + dDdu[0]*du[0];										\
											D1[1]	=	D[1] + dDdu[1]*du[0];										\
											D1[2]	=	D[2] + dDdu[2]*du[0];										\
											D2[0]	=	D[0] + dDdv[0]*dv[0];										\
											D2[1]	=	D[1] + dDdv[1]*dv[0];										\
											D2[2]	=	D[2] + dDdv[2]*dv[0];										\
											D3[0]	=	D[0] + dDdv[0]*dv[0] + dDdu[0]*dv[0];						\
											D3[1]	=	D[1] + dDdv[1]*dv[0] + dDdu[1]*dv[0];						\
											D3[2]	=	D[2] + dDdv[2]*dv[0] + dDdu[2]*dv[0];						\
																													\
											tex->lookup(color,D0,D1,D2,D3,lookup);									\
											res->real	=	color[0];												\
										}																			\
										res			++;																\
										D			+=	3;															\
										dDdu		+=	3;															\
										dDdv		+=	3;															\
										du++;																		\
										dv++;																		\
									}																				\
								}


#else
#define	ENVIRONMENTFEXPR_PRE
#endif

DEFFUNC(EnvironmentFloat			,"environment"				,"f=SFv!"		,ENVIRONMENTFEXPR_PRE,NULL_EXPR,NULL_EXPR,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	ENVIRONMENTFEXPR_PRE


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// shadow	"f=Sfv"
#ifndef INIT_SHADING
#define	SHADOWFEXPR_PRE			CTextureLookup	*lookup;															\
								TCode			*res;																\
								const TCode		*op3;																\
								int				i;																	\
								if ((lookup = (CTextureLookup *) parameterlist) == NULL) {							\
									TCode			*op2,*op1;														\
									int				numArguments;													\
									argumentcount(numArguments);													\
									TEXTUREPARAMETERS(4,(numArguments-4) >> 1);										\
									operand(1,op1);																	\
									operand(2,op2);																	\
									lookup->channel				=	(int) op2->real;								\
									lookup->lookupFloat			=	TRUE;											\
									if ((strcmp(op1->string,"raytrace")==0) || (strcmp(op1->string,"shadow") == 0)) {\
										lookup->environment		=	NULL;											\
									} else {																		\
										lookup->environment		=	getEnvironment(op1->string);					\
									}																				\
								}																					\
								if (lookup->environment == NULL) {													\
									float			*color;															\
									const int		numRealVertices = currentShadingState->numRealVertices;			\
																													\
									operand(0,res);																	\
									operand(3,op3);																	\
																													\
									color						=	(float *) ralloc(numRealVertices*3*sizeof(float));	\
																													\
									traceTransmission(color,(float *) op3,varying[VARIABLE_L],numRealVertices,tags,lookup);	\
																													\
									for (i=numRealVertices;i>0;i--,tags++,res++,color+=3) {							\
										if (*tags == 0) {															\
											res->real	=	1 - ((color[0] + color[1] + color[2]) / (float) 3);		\
										}																			\
									}																				\
								} else {																			\
									const float		*D;																\
									vector			color;															\
									CEnvironment	*tex;															\
									float			*dDdu		=	(float *) ralloc(numVertices*6*sizeof(float));	\
									float			*dDdv		=	dDdu + numVertices*3;							\
									const float		*du			=	varying[VARIABLE_DU];							\
									const float		*dv			=	varying[VARIABLE_DV];							\
									operand(0,res);																	\
									operand(3,op3);																	\
									D		=	(const float *) op3;												\
									tex		=	lookup->environment;												\
																													\
									duVector(dDdu,D);																\
									dvVector(dDdv,D);																\
																													\
									for (i=currentShadingState->numRealVertices;i>0;i--,tags++) {					\
										if (*tags == 0) {															\
											vector	D0,D1,D2,D3;													\
																													\
											D0[0]	=	D[0];														\
											D0[1]	=	D[1];														\
											D0[2]	=	D[2];														\
											D1[0]	=	D[0] + dDdu[0]*du[0];										\
											D1[1]	=	D[1] + dDdu[1]*du[0];										\
											D1[2]	=	D[2] + dDdu[2]*du[0];										\
											D2[0]	=	D[0] + dDdv[0]*dv[0];										\
											D2[1]	=	D[1] + dDdv[1]*dv[0];										\
											D2[2]	=	D[2] + dDdv[2]*dv[0];										\
											D3[0]	=	D[0] + dDdv[0]*dv[0] + dDdu[0]*dv[0];						\
											D3[1]	=	D[1] + dDdv[1]*dv[0] + dDdu[1]*dv[0];						\
											D3[2]	=	D[2] + dDdv[2]*dv[0] + dDdu[2]*dv[0];						\
																													\
											tex->lookup(color,D0,D1,D2,D3,lookup);									\
											res->real	=	color[0];												\
										}																			\
										res			++;																\
										D			+=	3;															\
										dDdu		+=	3;															\
										dDdv		+=	3;															\
										du++;																		\
										dv++;																		\
									}																				\
								}


#else
#define	SHADOWFEXPR_PRE
#endif

DEFFUNC(ShadowFloat			,"shadow"				,"f=SFp!"		,SHADOWFEXPR_PRE,NULL_EXPR,NULL_EXPR,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	SHADOWFEXPR_PRE


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// environment	"c=SFv"
#ifndef INIT_SHADING
#define	ENVIRONMENTCEXPR_PRE	CTextureLookup	*lookup;															\
								TCode			*res;																\
								const TCode		*op3;																\
								int				i;																	\
								if ((lookup = (CTextureLookup *) parameterlist) == NULL) {							\
									TCode			*op2,*op1;														\
									int				numArguments;													\
									argumentcount(numArguments);													\
									TEXTUREPARAMETERS(4,(numArguments-4) >> 1);										\
									operand(1,op1);																	\
									operand(2,op2);																	\
									lookup->channel				=	(int) op2->real;								\
									lookup->lookupFloat			=	FALSE;											\
									if ((strcmp(op1->string,"raytrace")==0) || (strcmp(op1->string,"reflection") == 0)) {		\
										lookup->environment		=	NULL;											\
									} else {																		\
										lookup->environment		=	getEnvironment(op1->string);					\
									}																				\
								}																					\
								if (lookup->environment == NULL) {													\
									const int		numRealVertices = currentShadingState->numRealVertices;			\
																													\
									operand(0,res);																	\
									operand(3,op3);																	\
																													\
									traceReflection((float *) res,varying[VARIABLE_P],(float *) op3,numRealVertices,tags,lookup);	\
								} else {																			\
									const float		*D;																\
									CEnvironment	*tex;															\
									float			*dDdu		=	(float *) ralloc(numVertices*6*sizeof(float));	\
									float			*dDdv		=	dDdu + numVertices*3;							\
									const float		*du			=	varying[VARIABLE_DU];							\
									const float		*dv			=	varying[VARIABLE_DV];							\
									operand(0,res);																	\
									operand(3,op3);																	\
									D		=	(const float *) op3;												\
									tex		=	lookup->environment;												\
																													\
									duVector(dDdu,D);																\
									dvVector(dDdv,D);																\
																													\
									for (i=currentShadingState->numRealVertices;i>0;i--,tags++) {					\
										if (*tags == 0) {															\
											vector	D0,D1,D2,D3;													\
																													\
											D0[0]	=	D[0];														\
											D0[1]	=	D[1];														\
											D0[2]	=	D[2];														\
											D1[0]	=	D[0] + dDdu[0]*du[0];										\
											D1[1]	=	D[1] + dDdu[1]*du[0];										\
											D1[2]	=	D[2] + dDdu[2]*du[0];										\
											D2[0]	=	D[0] + dDdv[0]*dv[0];										\
											D2[1]	=	D[1] + dDdv[1]*dv[0];										\
											D2[2]	=	D[2] + dDdv[2]*dv[0];										\
											D3[0]	=	D[0] + dDdv[0]*dv[0] + dDdu[0]*dv[0];						\
											D3[1]	=	D[1] + dDdv[1]*dv[0] + dDdu[1]*dv[0];						\
											D3[2]	=	D[2] + dDdv[2]*dv[0] + dDdu[2]*dv[0];						\
																													\
											tex->lookup(&res->real,D0,D1,D2,D3,lookup);								\
										}																			\
										res			+=	3;															\
										D			+=	3;															\
										dDdu		+=	3;															\
										dDdv		+=	3;															\
										du++;																		\
										dv++;																		\
									}																				\
								}


#else
#define	ENVIRONMENTCEXPR_PRE
#endif

DEFFUNC(EnvironmentColor			,"environment"				,"c=SFv!"		,ENVIRONMENTCEXPR_PRE,NULL_EXPR,NULL_EXPR,NULL_EXPR,PARAMETER_P | PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	ENVIRONMENTCEXPR_PRE


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// shadow	"c=SFv"
#ifndef INIT_SHADING
#define	SHADOWCEXPR_PRE			CTextureLookup	*lookup;															\
								TCode			*res;																\
								const TCode		*op3;																\
								int				i;																	\
								if ((lookup = (CTextureLookup *) parameterlist) == NULL) {							\
									TCode			*op2,*op1;														\
									int				numArguments;													\
									argumentcount(numArguments);													\
									TEXTUREPARAMETERS(4,(numArguments-4) >> 1);										\
									operand(1,op1);																	\
									operand(2,op2);																	\
									lookup->channel				=	(int) op2->real;								\
									lookup->lookupFloat			=	TRUE;											\
									if ((strcmp(op1->string,"raytrace")==0) || (strcmp(op1->string,"shadow") == 0)) {		\
										lookup->environment		=	NULL;											\
									} else {																		\
										lookup->environment		=	getEnvironment(op1->string);					\
									}																				\
								}																					\
								if (lookup->environment == NULL) {													\
									const int		numRealVertices = currentShadingState->numRealVertices;			\
																													\
									operand(0,res);																	\
									operand(3,op3);																	\
																													\
									traceTransmission((float *) res,(float *) op3,varying[VARIABLE_L],numRealVertices,tags,lookup);	\
																													\
									for (i=numRealVertices;i>0;i--,res+=3) {										\
										res[0].real	=	1 - res[0].real;											\
										res[1].real	=	1 - res[1].real;											\
										res[2].real	=	1 - res[2].real;											\
									}																				\
								} else {																			\
									const float		*D;																\
									CEnvironment	*tex;															\
									float			*dDdu		=	(float *) ralloc(numVertices*6*sizeof(float));	\
									float			*dDdv		=	dDdu + numVertices*3;							\
									const float		*du			=	varying[VARIABLE_DU];							\
									const float		*dv			=	varying[VARIABLE_DV];							\
									operand(0,res);																	\
									operand(3,op3);																	\
									D		=	(const float *) op3;												\
									tex		=	lookup->environment;												\
																													\
									duVector(dDdu,D);																\
									dvVector(dDdv,D);																\
																													\
									for (i=currentShadingState->numRealVertices;i>0;i--,tags++) {					\
										if (*tags == 0) {															\
											vector	D0,D1,D2,D3;													\
																													\
											D0[0]	=	D[0];														\
											D0[1]	=	D[1];														\
											D0[2]	=	D[2];														\
											D1[0]	=	D[0] + dDdu[0]*du[0];										\
											D1[1]	=	D[1] + dDdu[1]*du[0];										\
											D1[2]	=	D[2] + dDdu[2]*du[0];										\
											D2[0]	=	D[0] + dDdv[0]*dv[0];										\
											D2[1]	=	D[1] + dDdv[1]*dv[0];										\
											D2[2]	=	D[2] + dDdv[2]*dv[0];										\
											D3[0]	=	D[0] + dDdv[0]*dv[0] + dDdu[0]*dv[0];						\
											D3[1]	=	D[1] + dDdv[1]*dv[0] + dDdu[1]*dv[0];						\
											D3[2]	=	D[2] + dDdv[2]*dv[0] + dDdu[2]*dv[0];						\
																													\
											tex->lookup(&res->real,D0,D1,D2,D3,lookup);								\
										}																			\
										res			+=	3;															\
										D			+=	3;															\
										dDdu		+=	3;															\
										dDdv		+=	3;															\
										du++;																		\
										dv++;																		\
									}																				\
								}


#else
#define	SHADOWCEXPR_PRE
#endif

DEFFUNC(ShadowColor			,"shadow"				,"c=SFp!"		,SHADOWCEXPR_PRE,NULL_EXPR,NULL_EXPR,NULL_EXPR,PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_DU | PARAMETER_DV | PARAMETER_DERIVATIVE)

#undef	SHADOWCEXPR_PRE




// This macro is used to decode the filter parameter list
#define	FILTERPARAMETERS(start,num)																				\
								lookup				=	new CFilterLookup;										\
								parameterlist		=	lookup;													\
								dirty();																		\
								lookup->filter		=	RiCatmullRomFilter;										\
								lookup->width		=	1;														\
								{																				\
									int		i;																	\
									TCode	*param,*val;														\
																												\
									for (i=0;i<num;i++) {														\
										operand(i*2+start,param);												\
										operand(i*2+start+1,val);												\
																												\
										if (strcmp(param->string,"filter") == 0) {								\
											lookup->filter		=	currentRenderer->getFilter(val->string);	\
										} else if (strcmp(param->string,"width") == 0) {						\
											lookup->width		=	val->real;									\
										}																		\
									}																			\
								}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// filterstep "f=ff!"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef INIT_SHADING
#define	FILTERSTEP2EXPR_PRE	FUN3EXPR_PRE																		\
							CFilterLookup	*lookup;															\
							float			tmp;																\
							float			val;																\
							int				i;																	\
							float			step;																\
							if ((lookup = (CFilterLookup *) parameterlist) == NULL) {							\
								int				numArguments;													\
								argumentcount(numArguments);													\
								FILTERPARAMETERS(3,(numArguments-3) >> 1);										\
								lookup->compute();																\
							}																					\
							const	float			width	=	lookup->width;									\
							const	RtFilterFunc	filter	=	lookup->filter;

#define	FILTERSTEP2EXPR		tmp	=	0;																			\
							val	=	op2->real+width;															\
							i	=	NUMFILTERSTEPS-1;															\
							while(i>=0) {																		\
								if (op1->real > val)	break;													\
								step	=	min(lookup->valStep,val-op1->real);									\
								tmp		+=	lookup->vals[i]*step;												\
								val		-=	lookup->valStep;													\
								i--;																			\
							}																					\
							res->real	=	tmp / lookup->normalizer;


#define	FILTERSTEP2EXPR_UPDATE	FUN3EXPR_UPDATE(1,1,1)
#else
#define	FILTERSTEP2EXPR_PRE
#define	FILTERSTEP2EXPR
#define	FILTERSTEP2EXPR_UPDATE
#endif

DEFFUNC(FilterStep2			,"filterstep"				,"f=ff!"		,FILTERSTEP2EXPR_PRE,FILTERSTEP2EXPR,FUN3EXPR_UPDATE(1,1,1),NULL_EXPR,0)


#undef	FILTERSTEP2EXPR_PRE
#undef	FILTERSTEP2EXPR
#undef	FILTERSTEP2EXPR_UPDATE

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// filterstep "f=fff!"
// FIXME: What the heck is the third parameter for
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef INIT_SHADING
#define	FILTERSTEP3EXPR_PRE	FUN4EXPR_PRE																		\
							CFilterLookup	*lookup;															\
							float			tmp;																\
							float			val;																\
							int				i;																	\
							float			step;																\
							if ((lookup = (CFilterLookup *) parameterlist) == NULL) {							\
								int				numArguments;													\
								argumentcount(numArguments);													\
								FILTERPARAMETERS(3,(numArguments-3) >> 1);										\
								lookup->compute();																\
							}																					\
							const	float			width	=	lookup->width;									\
							const	RtFilterFunc	filter	=	lookup->filter;


#define	FILTERSTEP3EXPR		tmp	=	0;																			\
							val	=	op2->real+width;															\
							i	=	NUMFILTERSTEPS-1;															\
							while(i>=0) {																		\
								if (op1->real > val)	break;													\
								step	=	min(lookup->valStep,val-op1->real);									\
								tmp		+=	lookup->vals[i]*step;												\
								val		-=	lookup->valStep;													\
								i--;																			\
							}																					\
							res->real	=	tmp / lookup->normalizer;


#define	FILTERSTEP3EXPR_UPDATE	FUN4EXPR_UPDATE(1,1,1,1)
#else
#define	FILTERSTEP3EXPR_PRE
#define	FILTERSTEP3EXPR
#define	FILTERSTEP3EXPR_UPDATE
#endif

DEFFUNC(FilterStep3			,"filterstep"				,"f=fff!"		,FILTERSTEP3EXPR_PRE,FILTERSTEP3EXPR,FUN4EXPR_UPDATE(1,1,1,1),NULL_EXPR,0)


#undef	FILTERSTEP3EXPR_PRE
#undef	FILTERSTEP3EXPR
#undef	FILTERSTEP3EXPR_UPDATE

///////////////////////////////////////////////////
//
//	FIXME : missing functions :
//	bump


#include "giFunctions.h"
