//////////////////////////////////////////////////////////////////////
//
//                             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				:	execute.cpp
//  Classes				:	-
//  Description			:	This file implements the main shader execution
//
////////////////////////////////////////////////////////////////////////
#include <math.h>
#include <float.h>

#include "common/global.h"
#include "memory.h"
#include "output.h"
#include "renderer.h"
#include "shader.h"
#include "slcode.h"
#include "shading.h"
#include "noise.h"
#include "stats.h"
#include "photonMap.h"
#include "irradiance.h"
#include "bundles.h"
#include "error.h"
#include "executeMisc.h"

// This function is defined in shader.cpp for debugging purposes
void							debugFunction(float *);

// These functions are defined in init.cpp
void							convertColorFrom(float *,const float *,ECoordinateSystem);
void							convertColorTo(float *,const float *,ECoordinateSystem);

#define	saveLighting(__L)																	\
	if (numActive != 0) {																	\
		CShadedLight	*cLight		= 	NULL;												\
		int				numGlobals	=	cInstance->parent->numGlobals;						\
		if (*freeLights != NULL) {															\
			cLight					= *freeLights;											\
			*freeLights				= (*freeLights)->next;									\
			float**		savedState	= (float**) ralloc((2+numGlobals)*sizeof(float*));		\
			savedState[0]			= cLight->savedState[0];								\
			savedState[1]			= cLight->savedState[1];								\
			cLight->savedState		= savedState;											\
		} else {																			\
			cLight					= (CShadedLight*) ralloc(sizeof(CShadedLight));			\
			cLight->lightTags		= (int*)	ralloc(sizeof(int)*numVertices);			\
			cLight->savedState		= (float**) ralloc((2+numGlobals)*sizeof(float*));		\
			cLight->savedState[0]	= (float*)	ralloc(3*sizeof(float)*numVertices);		\
			cLight->savedState[1]	= (float*)	ralloc(3*sizeof(float)*numVertices);		\
			cLight->instance		= cInstance;											\
		}																					\
		cLight->next			= *lights;													\
		*lights					= cLight;													\
		memcpy(cLight->lightTags,tagStart,sizeof(int)*numVertices);							\
		memcpy(cLight->savedState[1],varying[VARIABLE_CL],3*sizeof(float)*numVertices);		\
		__L						= cLight->savedState[0];									\
		/*save extra variables if needed*/													\
		if (numGlobals != 0) {																\
			CShader		*cShader 	=	cInstance->parent;									\
			int			globNum		=	0;													\
			for (int i=0;i<cShader->numParameters;i++) {									\
				if (cShader->parameters[i].global != NULL) {								\
					CVariable *cVar = cShader->parameters[i].global;						\
					if ((cVar->container == CONTAINER_UNIFORM) || (cVar->container == CONTAINER_CONSTANT)) {					\
						cLight->savedState[2+globNum]  =	(float*) ralloc(sizeof(float)*cVar->numFloats);						\
						memcpy(cLight->savedState[2+globNum],varying[cVar->entry],sizeof(float)*cVar->numFloats);				\
					} else {																									\
						cLight->savedState[2+globNum]  =	(float*) ralloc(sizeof(float)*cVar->numFloats*numVertices);			\
						memcpy(cLight->savedState[2+globNum],varying[cVar->entry],sizeof(float)*cVar->numFloats*numVertices);	\
					}																		\
					globNum++;																\
				}																			\
			}																				\
		}																					\
	}

#define clearLighting() {												\
	currentShadingState->lightsExecuted = FALSE;						\
	*freeLights		=	*lights;										\
	*lights			=	NULL;											\
}

#define enterLightingConditional() {									\
	int tmpTag;															\
	int *lightTags	=	(*currentLight)->lightTags;						\
	tags			=	tagStart;										\
	for (i=numVertices;i>0;i--,tags++,lightTags++) {					\
		tmpTag = (*tags == 0);											\
		*tags += *lightTags;											\
		if (tmpTag && *tags) {											\
			numActive--;												\
			numPassive++;												\
		}																\
	}																	\
	tags = tagStart;													\
}

#define exitLightingConditional() {										\
	int tmpTag;															\
	int *lightTags	= (*currentLight)->lightTags;						\
	tags			=	tagStart;										\
	for (i=numVertices;i>0;i--,tags++,lightTags++) {					\
		tmpTag = *tags;													\
		*tags -= *lightTags;											\
		if (tmpTag && (*tags == 0)) {									\
			numActive++;												\
			numPassive--;												\
		}																\
	}																	\
	tags = tagStart;													\
}

#define enterFastLightingConditional() {								\
	int *lightTags	=	(*currentLight)->lightTags;						\
	tags			=	tagStart;										\
	for (i=numVertices;i>0;i--) {										\
		(*tags++) += (*lightTags++);									\
	}																	\
	tags = tagStart;													\
}

#define exitFastLightingConditional() {									\
	int *lightTags	= (*currentLight)->lightTags;						\
	tags			=	tagStart;										\
	for (i=numVertices;i>0;i--) {										\
		(*tags++) -= (*lightTags++);									\
	}																	\
	tags = tagStart;													\
}








///////////////////////////////////////////////////////////////////////
// Class				:	CShadingContext
// Method				:	execute
// Description			:	Execute a shader
// Return Value			:	-
// Comments				:
// Date last edited		:	11/28/2001
void	CShadingContext::execute(CProgrammableShaderInstance *cInstance) {
// At this point, the shader sends us the arrays for parameters/constants/variables/uniforms for the shader
	
//	The maximum allowed string size that can be handled
#define		MAX_SCRIPT_STRING_SIZE			256


#define		scripterror(mes)				{																	\
												error(CODE_SCRIPT,"\"%s\", (nullified)\n",mes);					\
												cInstance->parent->codeEntryPoint	=	-1;						\
												cInstance->parent->initEntryPoint	=	-1;						\
												goto	execEnd;												\
											}
//	Allocate temporary memory for the string and save it
#define		savestring(r,n)					{																	\
												int		strLen	=	strlen(n) + 1;								\
												int		strSize	=	(strLen & ~3) + 4;							\
												char	*strmem	=	(char *) ralloc(strSize);					\
												strcpy(strmem,n);												\
												r				=	strmem;										\
											}

//	Begin a conditional block execution
#define		beginConditional()				if (conditionals == NULL) {											\
												conditionals		=	(CConditional *) frameMemory->alloc(sizeof(CConditional));						\
												conditionals->next	=	NULL;									\
												conditionals->prev	=	NULL;									\
											}																	\
																												\
											conditionals->prev		=	lastConditional;						\
											lastConditional			=	conditionals;							\
											conditionals			=	lastConditional->next;
											

//	End a conditional block execution
#define		endConditional()				lastConditional->next	=	conditionals;							\
											conditionals			=	lastConditional;						\
											lastConditional			=	lastConditional->prev;

//	Retrieve a pointer to an operand and obtain it's size
#define		operand(i,n)					{																	\
												const TCode	ref	=	code[IP+i+2];								\
												n	= stuff[ref.reference.accessor][ref.reference.index];		\
											}

//	Retrieve an operand's size
#define		operandSize(i,n,s)				{																	\
												const TCode	ref	=	code[IP+i+2];								\
												n	= stuff[ref.reference.accessor][ref.reference.index];		\
												s	= ref.reference.numItems;									\
											}

// Retrieve the parameterlist
#define		parameterlist					cInstance->parameterLists[code[IP+1].arguments.plNumber]

#define		dirty()							if (cInstance->dirty == FALSE) {										\
												cInstance->dirty	=	TRUE;										\
												if (dirtyInstances == NULL)											\
													dirtyInstances	=	new CArray<CProgrammableShaderInstance *>;	\
												cInstance->attach();												\
												dirtyInstances->push(cInstance);									\
											}

//	Retrieve an integer operand (label references are integer)
#define		argument(i)						code[IP+i+2].integer;

//	Retrieve an integer operand (label references are integer)
#define		argumentCode(i)					code[IP+i+2]

//	Retrieve the number of arguments
#define		argumentcount(n)				n = code[IP+1].arguments.numArguments;

//	Control transfer
#define		jmp(n)							{																\
												IP				=	n;										\
												goto execStart;												\
											}

#define		hashLookupNegative(__dest)


//	Run the ambient light source shaders for the lP
#define		runAmbientLights()				if (!currentShadingState->ambientLightsExecuted) {				\
												const CAttributes		*currentAttributes	=	currentShadingState->currentObject->attributes;	\
												float					*Clsave;							\
												int						i;									\
																											\
												assert((numActive+numPassive) == numVertices);				\
												assert(numVertices == currentShadingState->numVertices);	\
												currentShadingState->numActive				=	numActive;	\
												currentShadingState->numPassive				=	numPassive;	\
												currentShadingState->ambientLightsExecuted	=	TRUE;		\
																											\
												if (*alights == NULL) {										\
													*alights					=		(CShadedLight*)	ralloc(sizeof(CShadedLight));							\
													(*alights)->savedState		=		(float**)		ralloc(2*sizeof(CShadedLight));							\
													(*alights)->savedState[1]	=		(float*)		ralloc(3*sizeof(float)*numVertices);					\
													(*alights)->savedState[0]	=		NULL;			/* ambient lights do not use tags or save L */			\
													(*alights)->lightTags		=		NULL;				\
													(*alights)->instance		=		NULL;				\
													(*alights)->next			=		NULL;				\
																											\
													Clsave	= (*alights)->savedState[1];					\
													for (i=0;i<numVertices;i++) {							\
														initv(Clsave,0,0,0);								\
														Clsave	+=	3;										\
													}														\
												}															\
																											\
												if (inShadow == FALSE) {									\
													CActiveLight			*cLight;						\
																											\
													for (cLight=currentAttributes->lightSources;cLight!=NULL;cLight=cLight->next) {	\
														CProgrammableShaderInstance	*light	=	cLight->light;						\
														if (!(light->flags & SHADERFLAGS_NONAMBIENT)) {								\
															currentShadingState->currentLightInstance	=	light;					\
															currentAttributes->initLightDefaults(numVertices,varying,cLight);		\
															light->illuminate(this);												\
														}													\
													}														\
												}															\
												assert(currentShadingState->numActive	==	numActive);		\
												assert(currentShadingState->numPassive	==	numPassive);	\
																											\
												currentShadingState->currentShaderInstance	=	cInstance;	\
											}


//	Run the light source shaders for the lP
#define		runLightsTemplate(lP,lN,lT,lightCategoryPre,lightCategoryCheck)									\
											int curLightingValid = currentShadingState->lightsExecuted;		\
											lightCategoryPre;												\
											if (curLightingValid) {											\
												const int	*aTag	=	tagStart;							\
												const int	*lTag	=	currentShadingState->lightingTags;	\
												int			i;												\
												curLightingValid = curLightingValid && 						\
													(currentShadingState->lightCategory == saveCat);		\
												/* memcmp is faster than a T32/xor/compare loop here */		\
												/* note: we should really only need to compare active */	\
												/*  shading points, but it's faster to compare all */		\
												curLightingValid = curLightingValid &&						\
													!memcmp(lN,currentShadingState->Ns,sizeof(float)*3*numVertices) &&		\
													!memcmp(lP,varying[VARIABLE_PS],sizeof(float)*3*numVertices) &&			\
													!memcmp(lT,currentShadingState->costheta,sizeof(float)*numVertices);	\
												/* we must still compare active tags, note this isn't */					\
												/* the same as tags being numerically equal */								\
												for (i=numVertices; curLightingValid && (i>0); i--) {						\
													curLightingValid = curLightingValid && (!*aTag++ & !*lTag++);			\
												}																			\
											}																\
											if (!curLightingValid) { 										\
												const CAttributes	*currentAttributes	=	currentShadingState->currentObject->attributes;	\
												assert((numActive+numPassive) == numVertices);				\
												assert(numVertices == currentShadingState->numVertices);	\
												currentShadingState->numActive		=	numActive;			\
												currentShadingState->numPassive		=	numPassive;			\
												currentShadingState->lightsExecuted	=	TRUE;				\
												currentShadingState->costheta		=	lT;					\
												currentShadingState->lightCategory	=	saveCat;			\
												/* memcpy is faster than a loop here */						\
												memcpy(varying[VARIABLE_PS],lP,numVertices*3*sizeof(float));					\
												memcpy(currentShadingState->Ns,lN,numVertices*3*sizeof(float));					\
												memcpy(currentShadingState->lightingTags,tagStart,numVertices*sizeof(int));		\
																											\
												/* clear all lights */										\
												*freeLights 	=	*lights;								\
												*lights			=	NULL;									\
																											\
												if (inShadow == FALSE) {									\
													CActiveLight			*cLight;						\
																											\
													for (cLight=currentAttributes->lightSources;cLight!=NULL;cLight=cLight->next) {		\
														CProgrammableShaderInstance	*light	=	cLight->light;							\
														lightCategoryCheck;																\
														if (light->flags & SHADERFLAGS_NONAMBIENT) {									\
															currentShadingState->currentLightInstance	=	light;						\
															currentAttributes->initLightDefaults(numVertices,varying,cLight);			\
															light->illuminate(this);													\
														}																				\
													}														\
												}															\
												assert(currentShadingState->numActive	==	numActive);		\
												assert(currentShadingState->numPassive	==	numPassive);	\
																											\
												currentShadingState->currentShaderInstance	=	cInstance;	\
											}

#define		CATEGORYLIGHT_PRE(lC)			int	runCat = 0,saveCat = 0;										\
											int	invertCatMatch = FALSE;										\
											if (*(lC->string) != '\0') {									\
												if (*(lC->string) == '-') {									\
													saveCat = -(runCat = currentRenderer->getGlobalID(lC->string+1));	\
													invertCatMatch = TRUE;									\
												} else {													\
													saveCat = runCat = currentRenderer->getGlobalID(lC->string);		\
												}															\
											}

#define		CATEGORYLIGHT_CHECK				if (light->categories != NULL) {								\
												int	validLight = FALSE;										\
												int *cCat;													\
												for (cCat=light->categories;(*cCat!=0);cCat++) {			\
													if (*cCat == runCat) {									\
														validLight = TRUE;									\
														break;												\
													}														\
												}															\
												if (invertCatMatch) {										\
													if (validLight)		continue;							\
												} else {													\
													if (!validLight)	continue;							\
												}															\
											} else if (!invertCatMatch) {									\
												continue;													\
											}

#define		runCategoryLights(lP,lN,lT,lC)	runLightsTemplate(lP,lN,lT,CATEGORYLIGHT_PRE(lC),CATEGORYLIGHT_CHECK)

#define		NORMALLIGHT_PRE					int saveCat = 0;

#define		runLights(lP,lN,lT)				runLightsTemplate(lP,lN,lT,NORMALLIGHT_PRE,NULL_EXPR)

// The misc macros
#define		DEFLINKOPCODE(name,text,nargs)				case OPCODE_##name:		
#define		DEFLINKFUNC(name,text,prototype,par)		case FUNCTION_##name:

// Break the shader execution
#define		BREAK							goto execEnd;



	//	The	shading variables and junk
	TCode						**stuff[6];			// Where we keep pointers to the variables
	int							IP;					// Isn't it obvious ?
	ESlCode						opcode;				// :)
	CConditional				*lastConditional;	// The last conditional
	int							numActive;			// The number of active points being shaded
	int							numPassive;			// The number of passive points being not shaded (numPassive+numActive = numVertices)
	int							*tags;				// Execution tags
	int							*tagStart;
	int							currentVertex;		// The current vertex being executed
	CShader						*currentShader			=	cInstance->parent;
	TCode						*code;
	int							numVertices;
	float						**varying;
	CShadedLight				**lights;
	CShadedLight				**alights;
	CShadedLight				**currentLight;
	CShadedLight				**freeLights;
	CShaderCache				*cCache;
	CGatherBundle				*lastGather;		// Pointer to the last gather bundle

	assert((currentShadingState->numActive+currentShadingState->numPassive) == currentShadingState->numVertices);

	currentShadingState->currentShaderInstance	=	cInstance;
	code										=	currentShader->codeArea;
	IP											=	currentShader->codeEntryPoint;
	tagStart									=	currentShadingState->tags;

	// Allocate the shader variables
	cCache								=	currentShader->cache;
	if (cCache == NULL)	cCache			=	newCache(currentShader);
	currentShader->cache				=	cCache->shaderNext;

	// Save this stuff for fast access
	numVertices							=	currentShadingState->numVertices;
	varying								=	currentShadingState->varying;
	lights								=	&currentShadingState->lights;
	alights								=	&currentShadingState->alights;
	currentLight						=	&currentShadingState->currentLight;
	freeLights							=	&currentShadingState->freeLights;

	// Set the access arrays
	stuff[SL_IMMEDIATE_OPERAND]			=	currentShader->constantEntries;				// Immediate operands
	stuff[SL_PARAMETER_OPERAND]			=	cInstance->parameterEntries;				// Parameters
	stuff[SL_GLOBAL_OPERAND]			=	(TCode **) varying;							// Varying globals
	stuff[SL_UNIFORM_OPERAND]			=	cCache->uniforms;							// Shader uniform local variables
	stuff[SL_VARYING_OPERAND]			=	cCache->varyings;							// Shader varying local variables

	numActive							=	currentShadingState->numActive;
	numPassive							=	currentShadingState->numPassive;
	lastConditional						=	NULL;										// The last conditional block

	// Execute
execStart:
	opcode	=	(ESlCode)	code[IP].integer;	// Get the opcode

	tags	=	tagStart;						// Set the tags to the start

	if (code[IP+1].arguments.uniform) {			// If the opcode is uniform , execute once
#define		DEFOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params)					\
			case OPCODE_##name:																		\
			{																						\
				expr_pre;																			\
				expr;																				\
				expr_post;																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}

#define		DEFSHORTOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params)				\
			case OPCODE_##name:																		\
			{																						\
				expr_pre;																			\
				expr;																				\
				expr_post;																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}


#define		DEFFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par)					\
			case FUNCTION_##name:																	\
			{																						\
				expr_pre;																			\
				expr;																				\
				expr_post;																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}

#define		DEFLIGHTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par)				\
			case FUNCTION_##name:																	\
			{																						\
				scripterror("invalid uniform lighting call");										\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}

#define		DEFSHORTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par)				\
			case FUNCTION_##name:																	\
			{																						\
				expr_pre;																			\
				expr;																				\
				expr_post;																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}

		switch(opcode) {

#include "scriptOpcodes.h"

#include "scriptFunctions.h"

		default:
			error(CODE_BUG,"Opcode conflict");
			goto execEnd;
		}

		// Resume executing instructions
		IP	+=	code[IP+1].arguments.numCodes;
		goto execStart;

#undef DEFOPCODE
#undef DEFSHORTOPCODE
#undef DEFFUNC
#undef DEFLIGHTFUNC
#undef DEFSHORTFUNC


	} else {
		if (numPassive != 0) {					// If we have some vertices that are passive, be more careful
#define		DEFOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params)					\
			case OPCODE_##name:																		\
			{																						\
				expr_pre;																			\
				for (currentVertex=numVertices;currentVertex>0;currentVertex--,tags++) {			\
					if (*tags == 0) {																\
						expr;																		\
					}																				\
					expr_update;																	\
				}																					\
				expr_post																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}


#define		DEFSHORTOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params)				\
			case OPCODE_##name:																		\
			{																						\
				expr_pre;																			\
				for (currentVertex=currentShadingState->numRealVertices;currentVertex>0;currentVertex--,tags++) {			\
					if (*tags == 0) {																\
						expr;																		\
					}																				\
					expr_update;																	\
				}																					\
				expr_post																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}


#define		DEFFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par)					\
			case FUNCTION_##name:																	\
			{																						\
				expr_pre;																			\
				for (currentVertex=numVertices;currentVertex>0;currentVertex--,tags++) {			\
					if (*tags == 0) {																\
						expr;																		\
					}																				\
					expr_update;																	\
				}																					\
				expr_post																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}

#define		DEFLIGHTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par)				\
			case FUNCTION_##name:																	\
			{																						\
				expr_pre;																			\
				for (currentVertex=numVertices;currentVertex>0;currentVertex--,tags++) {			\
					if (*tags == 0) {																\
						expr;																		\
					}																				\
					expr_update;																	\
				}																					\
				expr_post																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}
			
#define		DEFSHORTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par)				\
			case FUNCTION_##name:																	\
			{																						\
				expr_pre;																			\
				for (currentVertex=currentShadingState->numRealVertices;currentVertex>0;currentVertex--,tags++) {			\
					if (*tags == 0) {																\
						expr;																		\
					}																				\
					expr_update;																	\
				}																					\
				expr_post																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}


			switch(opcode) {

#include "scriptOpcodes.h"

#include "scriptFunctions.h"

			default:
				error(CODE_BUG,"Opcode conflict");
				goto execEnd;
			}

			IP	+=	code[IP+1].arguments.numCodes;
			goto execStart;
		} else {

#undef DEFOPCODE
#undef DEFSHORTOPCODE
#undef DEFFUNC
#undef DEFLIGHTFUNC
#undef DEFSHORTFUNC

#define		DEFOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params)					\
			case OPCODE_##name:																		\
			{																						\
				expr_pre;																			\
				for (currentVertex=numVertices;currentVertex>0;currentVertex--) {					\
					expr;																			\
					expr_update;																	\
				}																					\
				expr_post																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}

#define		DEFSHORTOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params)				\
			case OPCODE_##name:																		\
			{																						\
				expr_pre;																			\
				for (currentVertex=currentShadingState->numRealVertices;currentVertex>0;currentVertex--) {					\
					expr;																			\
					expr_update;																	\
				}																					\
				expr_post																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}


#define		DEFFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par)					\
			case FUNCTION_##name:																	\
			{																						\
				expr_pre;																			\
				for (currentVertex=numVertices;currentVertex>0;currentVertex--) {					\
					expr;																			\
					expr_update;																	\
				}																					\
				expr_post																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}

#define		DEFLIGHTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par)				\
			case FUNCTION_##name:																	\
			{																						\
				expr_pre;																			\
				for (currentVertex=numVertices;currentVertex>0;currentVertex--,tags++) {			\
					if (*tags == 0) {																\
						expr;																		\
					}																				\
					expr_update;																	\
				}																					\
				expr_post																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}


#define		DEFSHORTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par)				\
			case FUNCTION_##name:																	\
			{																						\
				expr_pre;																			\
				for (currentVertex=currentShadingState->numRealVertices;currentVertex>0;currentVertex--) {					\
					expr;																			\
					expr_update;																	\
				}																					\
				expr_post																			\
				IP	+=	code[IP+1].arguments.numCodes;												\
				goto execStart;																		\
			}

			switch(opcode) {

#include "scriptOpcodes.h"

#include "scriptFunctions.h"

			default:
				error(CODE_BUG,"Opcode conflict");
				goto execEnd;
			}

			IP	+=	code[IP+1].arguments.numCodes;
			goto execStart;
		}

#undef DEFOPCODE
#undef DEFSHORTOPCODE
#undef DEFFUNC
#undef DEFLIGHTFUNC
#undef DEFSHORTFUNC

	}


	goto execStart;
execEnd:

	// Restore the cache for the shader
	cCache->shaderNext		=	currentShader->cache;
	currentShader->cache	=	cCache;

	// Make sure we save the ambient contribution if there has been no illuminate/solar executed
	if (currentShader->type == SL_LIGHTSOURCE) {
		if (!(currentShader->usedParameters & PARAMETER_NONAMBIENT)) {
			float	*Cl		=	varying[VARIABLE_CL];
			float	*Ol		=	varying[VARIABLE_OL];
			float	*Clsave;
			
			// Save the ambient junk
			Clsave	= (*alights)->savedState[1];
			tags	= tagStart;
			for (int i=0;i<numVertices;i++,Cl+=3,Ol+=3,Clsave+=3) {
				if (*tags==0) {
					addvv(Clsave,Cl);
				}
				tags++;
			}
		}
	}

// Undefine junk
#undef		MAX_SCRIPT_STRING_SIZE
#undef		savestring
#undef		allocbuffer
#undef		freebuffer
#undef		beginConditional
#undef		endConditional
#undef		operand
#undef		dirty
#undef		parameterlist
#undef		argument
#undef		argumentcount
#undef		jmp
#undef		runAmbientLights
#undef		runLightsTemplate
#undef		CATEGORYLIGHT_PRE
#undef		CATEGORYLIGHT_CHECK
#undef		runCategoryLights
#undef		NORMALLIGHT_PRE
#undef		runLights
#undef		firstLight
#undef		nextLight
#undef		allLights
#undef		currentLight
#undef		saveLight	
#undef		uniformGlobal
#undef		varyingGlobal
#undef		DEFOPCODE
#undef		DEFFUNC
#undef		DEFLINKOPCODE
#undef		DEFLINKFUNC
#undef		BREAK
}






