1 //////////////////////////////////////////////////////////////////////
2 //
3 //                             Pixie
4 //
5 // Copyright � 1999 - 2003, Okan Arikan
6 //
7 // Contact: okan@cs.utexas.edu
8 //
9 //	This library is free software; you can redistribute it and/or
10 //	modify it under the terms of the GNU Lesser General Public
11 //	License as published by the Free Software Foundation; either
12 //	version 2.1 of the License, or (at your option) any later version.
13 //
14 //	This library is distributed in the hope that it will be useful,
15 //	but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 //	Lesser General Public License for more details.
18 //
19 //	You should have received a copy of the GNU Lesser General Public
20 //	License along with this library; if not, write to the Free Software
21 //	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 //
23 ///////////////////////////////////////////////////////////////////////
24 ///////////////////////////////////////////////////////////////////////
25 //
26 //  File				:	execute.cpp
27 //  Classes				:	-
28 //  Description			:	This file implements the main shader execution
29 //
30 ////////////////////////////////////////////////////////////////////////
31 #include <math.h>
32 #include <float.h>
33 #include <stddef.h>
34 
35 #include "common/global.h"
36 #include "memory.h"
37 #include "shader.h"
38 #include "slcode.h"
39 #include "shading.h"
40 #include "noise.h"
41 #include "photonMap.h"
42 #include "texture3d.h"
43 #include "irradiance.h"
44 #include "bundles.h"
45 #include "error.h"
46 #include "renderer.h"
47 #include "surface.h"
48 #include "texture.h"
49 #include "shaderPl.h"
50 #include "ri_config.h"
51 
52 // This function is defined in shader.cpp for debugging purposes
53 void							debugFunction(float *);
54 
55 // These functions are defined in init.cpp
56 void							convertColorFrom(float *,const float *,ECoordinateSystem);
57 void							convertColorTo(float *,const float *,ECoordinateSystem);
58 
59 
60 // Lighting helpers
61 #define	saveLighting(__L)																	\
62 	if (numActive != 0) {																	\
63 		CShadedLight	*cLight		= 	NULL;												\
64 		const int		numGlobals	=	cInstance->parent->numGlobals;						\
65 		if (*freeLights != NULL) {															\
66 			cLight					= *freeLights;											\
67 			*freeLights				= (*freeLights)->next;									\
68 			float**		savedState	= (float**) ralloc((2+numGlobals)*sizeof(float*),threadMemory);		\
69 			savedState[0]			= cLight->savedState[0];								\
70 			savedState[1]			= cLight->savedState[1];								\
71 			cLight->savedState		= savedState;											\
72 		} else {																			\
73 			cLight					= (CShadedLight*) ralloc(sizeof(CShadedLight),threadMemory);		\
74 			cLight->lightTags		= (int*)	ralloc(sizeof(int)*numVertices,threadMemory);			\
75 			cLight->savedState		= (float**) ralloc((2+numGlobals)*sizeof(float*),threadMemory);		\
76 			cLight->savedState[0]	= (float*)	ralloc(3*sizeof(float)*numVertices,threadMemory);		\
77 			cLight->savedState[1]	= (float*)	ralloc(3*sizeof(float)*numVertices,threadMemory);		\
78 			cLight->instance		= cInstance;											\
79 		}																					\
80 		cLight->next			= *lights;													\
81 		*lights					= cLight;													\
82 		memcpy(cLight->lightTags,tagStart,sizeof(int)*numVertices);							\
83 		memcpy(cLight->savedState[1],varying[VARIABLE_CL],3*sizeof(float)*numVertices);		\
84 		__L						= cLight->savedState[0];									\
85 		/*save extra variables if needed*/													\
86 		if (numGlobals != 0) {																\
87 			int							globNum		=	0;									\
88 			CVariable					*cVariable;											\
89 			for (cVariable=cInstance->parameters;cVariable!=NULL;cVariable=cVariable->next) {	\
90 				if (cVariable->storage == STORAGE_GLOBAL) {									\
91 					/* globals come from the global varyings */								\
92 					if ((cVariable->container == CONTAINER_UNIFORM) || (cVariable->container == CONTAINER_CONSTANT)) {					\
93 						cLight->savedState[2+globNum]  =	(float*) ralloc(sizeof(float)*cVariable->numFloats,threadMemory);			\
94 						memcpy(cLight->savedState[2+globNum],varying[cVariable->entry],sizeof(float)*cVariable->numFloats);				\
95 					} else {																											\
96 						cLight->savedState[2+globNum]  =	(float*) ralloc(sizeof(float)*cVariable->numFloats*numVertices,threadMemory);	\
97 						memcpy(cLight->savedState[2+globNum],varying[cVariable->entry],sizeof(float)*cVariable->numFloats*numVertices);		\
98 					}																		\
99 					globNum++;																\
100 				} else if (cVariable->storage == STORAGE_MUTABLEPARAMETER) {				\
101 					/* mutable parameters come from the shader varyings */					\
102 					if ((cVariable->container == CONTAINER_UNIFORM) || (cVariable->container == CONTAINER_CONSTANT)) {										\
103 						cLight->savedState[2+globNum]  =	(float*) ralloc(sizeof(float)*cVariable->numFloats,threadMemory);								\
104 						memcpy(cLight->savedState[2+globNum],stuff[SL_VARYING_OPERAND][cVariable->entry],sizeof(float)*cVariable->numFloats);				\
105 					} else {																																\
106 						cLight->savedState[2+globNum]  =	(float*) ralloc(sizeof(float)*cVariable->numFloats*numVertices,threadMemory);					\
107 						memcpy(cLight->savedState[2+globNum],stuff[SL_VARYING_OPERAND][cVariable->entry],sizeof(float)*cVariable->numFloats*numVertices);	\
108 					}																		\
109 					globNum++;																\
110 				}																			\
111 			}																				\
112 		}																					\
113 	}
114 
115 #define clearLighting() {												\
116 	currentShadingState->lightsExecuted = FALSE;						\
117 	*freeLights		=	*lights;										\
118 	*lights			=	NULL;											\
119 }
120 
121 #define enterLightingConditional() {									\
122 	const int	*lightTags	=	(*currentLight)->lightTags;				\
123 	tags			=	tagStart;										\
124 	for (int i=numVertices;i>0;--i,++tags,++lightTags) {				\
125 		const int tmpTag = (*tags == 0);								\
126 		*tags += *lightTags;											\
127 		if (tmpTag && *tags) {											\
128 			--numActive;												\
129 			++numPassive;												\
130 		}																\
131 	}																	\
132 	tags = tagStart;													\
133 }
134 
135 #define exitLightingConditional() {										\
136 	const int	*lightTags	= (*currentLight)->lightTags;				\
137 	tags			=	tagStart;										\
138 	for (int i=numVertices;i>0;--i,++tags,++lightTags) {				\
139 		const int tmpTag = *tags;										\
140 		*tags -= *lightTags;											\
141 		if (tmpTag && (*tags == 0)) {									\
142 			++numActive;												\
143 			--numPassive;												\
144 		}																\
145 	}																	\
146 	tags = tagStart;													\
147 }
148 
149 #define enterFastLightingConditional() {								\
150 	const int *lightTags	=	(*currentLight)->lightTags;				\
151 	tags			=	tagStart;										\
152 	for (int i=numVertices;i>0;--i) {									\
153 		(*tags++) += (*lightTags++);									\
154 	}																	\
155 	tags = tagStart;													\
156 }
157 
158 #define exitFastLightingConditional() {									\
159 	const int *lightTags	= (*currentLight)->lightTags;				\
160 	tags			=	tagStart;										\
161 	for (int i=numVertices;i>0;--i) {									\
162 		(*tags++) -= (*lightTags++);									\
163 	}																	\
164 	tags = tagStart;													\
165 }
166 
167 
168 
169 
170 
171 
172 
173 ///////////////////////////////////////////////////////////////////////
174 // Class				:	CShadingContext
175 // Method				:	execute
176 // Description			:	Execute a shader
177 // Return Value			:	-
178 // Comments				:
execute(CProgrammableShaderInstance * cInstance,float ** locals)179 void	CShadingContext::execute(CProgrammableShaderInstance *cInstance,float **locals) {
180 // At this point, the shader sends us the arrays for parameters/constants/variables/uniforms for the shader
181 
182 #define		scripterror(mes)				{																	\
183 												CRenderer::offendingObject	=	currentShadingState->currentObject;	\
184 												error(CODE_SCRIPT,"\"%s\", in shader \"%s\" (nullified)\n",mes,cInstance->getName()); \
185 												cInstance->parent->codeEntryPoint	=	-1;						\
186 												cInstance->parent->initEntryPoint	=	-1;						\
187 												goto	execEnd;												\
188 											}
189 //	Allocate temporary memory for the string and save it
190 #define		savestring(r,n)					{																	\
191 												const int	strLen	=	(int) strlen(n) + 1;					\
192 												const int	strSize	=	(strLen & ~3) + 4;						\
193 												char		*strmem	=	(char *) ralloc(strSize,threadMemory);	\
194 												strcpy(strmem,n);												\
195 												r				=	strmem;										\
196 											}
197 
198 //	Begin a conditional block execution
199 #define		beginConditional()				if (conditionals == NULL) {											\
200 												conditionals		=	new CConditional;						\
201 												conditionals->next	=	NULL;									\
202 												conditionals->prev	=	NULL;									\
203 											}																	\
204 																												\
205 											conditionals->prev		=	lastConditional;						\
206 											lastConditional			=	conditionals;							\
207 											conditionals			=	lastConditional->next;
208 
209 
210 //	End a conditional block execution
211 #define		endConditional()				lastConditional->next	=	conditionals;							\
212 											conditionals			=	lastConditional;						\
213 											lastConditional			=	lastConditional->prev;
214 
215 //	Retrieve a pointer to an operand and obtain it's size
216 #define		operand(i,n,t)					{																	\
217 												const TArgument	*ref	=	code->arguments + i;				\
218 												n	= (t) stuff[ref->accessor][ref->index];						\
219 											}
220 
221 //	Retrieve an operand's size
222 #define		operandSize(i,n,s,t)			{																	\
223 												const TArgument	*ref	=	code->arguments + i;				\
224 												n	= (t) stuff[ref->accessor][ref->index];						\
225 												s	= ref->numItems;											\
226 											}
227 
228 #define		operandNumItems(i)				code->arguments[i].numItems
229 
230 #define		operandBytesPerItem(i)			code->arguments[i].bytesPerItem
231 
232 #define		operandVaryingStep(i)			code->arguments[i].varyingStep
233 
234 
235 // Use this macro to start processing a parameter list
236 #define		plBegin(__class,__start)		/* Create a hash key using shader and instruction */					\
237 											const uintptr_t	hashKey	=	((uintptr_t) cInstance + (uintptr_t) code / sizeof(TCode)) & (PL_HASH_SIZE-1);		\
238 											__class			*lookup	=	NULL;										\
239 											CPLLookup		*prev	=	NULL;										\
240 											CPLLookup		*current;												\
241 											for (current=plHash[hashKey];current!=NULL;prev=current,current=current->next) {	\
242 												/* Is this a hit ?*/												\
243 												if ((current->instance == cInstance) && (current->code == code)) {	\
244 													lookup	=	(__class *) current;								\
245 													/* Move the hit to the beginning of the list */					\
246 													if (prev != NULL) {												\
247 														prev->next		=	current->next;							\
248 														current->next	=	plHash[hashKey];						\
249 														plHash[hashKey]	=	current;								\
250 													}																\
251 													break;															\
252 												}																	\
253 											}																		\
254 																													\
255 																													\
256 											/* Look at the hash to see if we've computed this before	*/			\
257 											if (lookup == NULL) {													\
258 																													\
259 												/* Get the number of arguments we have */							\
260 												const int	num			=	code->numArguments;						\
261 																													\
262 												/* Allocate temporary memory */										\
263 												CPLLookup::TParamBinding	*uniforms	=	(CPLLookup::TParamBinding *) ralloc(num*2*sizeof(CPLLookup::TParamBinding),threadMemory);	\
264 												CPLLookup::TParamBinding	*varyings	=	uniforms + num;			\
265 																													\
266 												/* Create a new lookup	*/											\
267 												lookup						=	new __class;						\
268 												lookup->instance			=	cInstance;							\
269 												lookup->code				=	code;								\
270 												lookup->uniforms			=	uniforms;							\
271 												lookup->varyings			=	varyings;							\
272 												lookup->next				=	plHash[hashKey];					\
273 												plHash[hashKey]				=	lookup;								\
274 																													\
275 												/* Decode the PL */													\
276 												for (int i=__start;i<num;++i) {										\
277 													/* Get the parameter name */									\
278 													const char **param;												\
279 													operand(i,param,const char **);									\
280 													/* Get the parameter info */									\
281 													++i;															\
282 													const int	uniform	=	operandVaryingStep(i) == 0;				\
283 													const int	step	=	operandBytesPerItem(i)*operandNumItems(i);	\
284 													/* Decode the data only for uniform parameters */				\
285 													void		*data	=	NULL;									\
286 													if (uniform) {	operand(i,data,void *);	}						\
287 																													\
288 													/* Ask the lookup to find the variable */						\
289 													lookup->bind(*param,i,step,data,cInstance);						\
290 												}																	\
291 																													\
292 												/* Allocate the final memory for the bound variables */				\
293 												lookup->uniforms	=	new CPLLookup::TParamBinding[lookup->numUniforms+lookup->numVaryings];		\
294 												lookup->varyings	=	lookup->uniforms + lookup->numUniforms;		\
295 												/* Copy the saved data over to the final resting place */			\
296 												memcpy(lookup->uniforms,uniforms,lookup->numUniforms*sizeof(CPLLookup::TParamBinding));	\
297 												memcpy(lookup->varyings,varyings,lookup->numVaryings*sizeof(CPLLookup::TParamBinding));	\
298 											}																		\
299 																													\
300 											/* Get a local copy of the scratch */									\
301 											CShadingScratch		*scratch		=	&(currentShadingState->scratch);	\
302 																														\
303 											/* Overwrite some of the initial values from the attributes */				\
304 											const CAttributes *cAttributes		=	currentShadingState->currentObject->attributes;	\
305 											lookup->init(scratch,cAttributes);														\
306 																																	\
307 											/* Init the varyings	*/												\
308 											char	**PL_VARIABLES	=	(char **) ralloc(lookup->numVaryings*sizeof(char *),threadMemory);	\
309 											const CPLLookup::TParamBinding	*cBinding	=	lookup->varyings;		\
310 											for (int var=0;var<lookup->numVaryings;++var,++cBinding) {				\
311 												operand(cBinding->opIndex,PL_VARIABLES[var],char *);				\
312 											}																		\
313 																													\
314 											/* Init the uniforms	*/												\
315 											cBinding	=	lookup->uniforms;										\
316 											for (int var=0;var<lookup->numUniforms;++var,++cBinding) {				\
317 												char	*tmp;														\
318 												operand(cBinding->opIndex,tmp,char *);								\
319 												memcpy((char *) scratch + cBinding->dest,tmp,cBinding->step);		\
320 											}																		\
321 																													\
322 											/* let the lookup do any massaging needed */							\
323 											lookup->postBind(scratch);
324 
325 // Use this macro to get the scratch variables updated
326 #define		plReady()						cBinding	=	lookup->varyings;										\
327 											for (int var=0;var<lookup->numVaryings;++var,++cBinding) {				\
328 												memcpy((char *) scratch + cBinding->dest,PL_VARIABLES[var],cBinding->step);	\
329 											}
330 
331 // Use this variable to step over the variables defined in the parameter list
332 #define		plStep()						for (int var=0;var<lookup->numVaryings;++var) {							\
333 												PL_VARIABLES[var]	+=	lookup->varyings[var].step;					\
334 											}
335 
336 // Use this macro to restore the scratch variables that have been overwritten
337 #define		plEnd()
338 
339 //	Retrieve an integer operand (label references are integer)
340 #define		argument(i)						code->arguments[i].index
341 
342 //	Retrieve the number of arguments
343 #define		argumentcount(n)				n = code->numArguments
344 
345 //	Control transfer
346 #define		jmp(n)							{																\
347 												code		=	currentShader->codeArea + n;				\
348 												goto execStart;												\
349 											}
350 
351 //	Expand the results from primary shading points to all
352 #define		expandVector(__res)				if (numVertices != currentShadingState->numRealVertices) {		\
353 												const float	*src	=	__res - currentShadingState->numRealVertices*3;			\
354 												for (int i=currentShadingState->numRealVertices;i>0;--i) {						\
355 													movvv(__res,src);	__res	+=	3;	src	+=	3;			\
356 													movvv(__res,src);	__res	+=	3;	src	+=	3;			\
357 												}															\
358 											}
359 
360 //	Expand the results from primary shading points to all
361 #define		expandFloat(__res)				if (numVertices != currentShadingState->numRealVertices) {		\
362 												const float	*src	=	__res - currentShadingState->numRealVertices;			\
363 												for (int i=currentShadingState->numRealVertices;i>0;--i) {						\
364 													*__res++	=	*src++;									\
365 													*__res++	=	*src++;									\
366 												}															\
367 											}
368 
369 
370 //	Run the ambient light source shaders for the lP
371 #define		runAmbientLights()				if (!currentShadingState->ambientLightsExecuted) {				\
372 												const CAttributes		*currentAttributes	=	currentShadingState->currentObject->attributes;	\
373 												float					*Clsave;							\
374 																											\
375 												assert((numActive+numPassive) == numVertices);				\
376 												assert(numVertices == currentShadingState->numVertices);	\
377 												currentShadingState->numActive				=	numActive;	\
378 												currentShadingState->numPassive				=	numPassive;	\
379 												currentShadingState->ambientLightsExecuted	=	TRUE;		\
380 																											\
381 												if (*alights == NULL) {										\
382 													*alights					=		(CShadedLight*)	ralloc(sizeof(CShadedLight),threadMemory);				\
383 													(*alights)->savedState		=		(float**)		ralloc(2*sizeof(CShadedLight),threadMemory);			\
384 													(*alights)->savedState[1]	=		(float*)		ralloc(3*sizeof(float)*numVertices,threadMemory);		\
385 													(*alights)->savedState[0]	=		NULL;			/* ambient lights do not use tags or save L */			\
386 													(*alights)->lightTags		=		NULL;				\
387 													(*alights)->instance		=		NULL;				\
388 													(*alights)->next			=		NULL;				\
389 																											\
390 													Clsave	= (*alights)->savedState[1];					\
391 													for (int i=numVertices;i>0;--i,Clsave+=3) {				\
392 														initv(Clsave,0);									\
393 													}														\
394 												}															\
395 																											\
396 												if (inShadow == FALSE) {									\
397 																											\
398 													for (CActiveLight	*cLight=currentAttributes->lightSources;cLight!=NULL;cLight=cLight->next) {	\
399 														CProgrammableShaderInstance	*light	=	cLight->light;						\
400 														if (!(light->flags & SHADERFLAGS_NONAMBIENT)) {								\
401 															memBegin(shaderStateMemory);											\
402 															currentShadingState->currentLightInstance			=	light;			\
403 															currentShadingState->locals[ACCESSOR_LIGHTSOURCE]	=	light->prepare(shaderStateMemory,varying,numVertices);	\
404 															light->illuminate(this,currentShadingState->locals[ACCESSOR_LIGHTSOURCE]);										\
405 															memEnd(shaderStateMemory);						\
406 														}													\
407 													}														\
408 												}															\
409 												assert(currentShadingState->numActive	==	numActive);		\
410 												assert(currentShadingState->numPassive	==	numPassive);	\
411 																											\
412 												currentShadingState->currentShaderInstance	=	cInstance;	\
413 											}
414 
415 
416 //	Run the light source shaders for the lP
417 #define		runLightsTemplate(lP,lN,lT,lightCategoryPre,lightCategoryCheck)									\
418 											int curLightingValid = currentShadingState->lightsExecuted;		\
419 											lightCategoryPre;												\
420 											if (curLightingValid) {											\
421 												const int	*aTag	=	tagStart;							\
422 												const int	*lTag	=	currentShadingState->lightingTags;	\
423 												curLightingValid = curLightingValid && 						\
424 													(currentShadingState->lightCategory == saveCat);		\
425 												/* memcmp is faster than a T32/xor/compare loop here */		\
426 												/* note: we should really only need to compare active */	\
427 												/*  shading points, but it's faster to compare all */		\
428 												curLightingValid = curLightingValid &&						\
429 													!memcmp(lN,currentShadingState->Ns,sizeof(float)*3*numVertices) &&		\
430 													!memcmp(lP,varying[VARIABLE_PS],sizeof(float)*3*numVertices) &&			\
431 													!memcmp(lT,currentShadingState->costheta,sizeof(float)*numVertices);	\
432 												/* we must still compare active tags, note this isn't */					\
433 												/* the same as tags being numerically equal */								\
434 												for (int i=numVertices; curLightingValid && (i>0); --i) {					\
435 													curLightingValid = curLightingValid && (!*aTag++ & !*lTag++);			\
436 												}																			\
437 											}																\
438 											if (!curLightingValid) { 										\
439 												const CAttributes	*currentAttributes	=	currentShadingState->currentObject->attributes;	\
440 												assert((numActive+numPassive) == numVertices);				\
441 												assert(numVertices == currentShadingState->numVertices);	\
442 												currentShadingState->numActive		=	numActive;			\
443 												currentShadingState->numPassive		=	numPassive;			\
444 												currentShadingState->lightsExecuted	=	TRUE;				\
445 												currentShadingState->costheta		=	lT;					\
446 												currentShadingState->lightCategory	=	saveCat;			\
447 												/* memcpy is faster than a loop here */						\
448 												memcpy(varying[VARIABLE_PS],lP,numVertices*3*sizeof(float));					\
449 												memcpy(currentShadingState->Ns,lN,numVertices*3*sizeof(float));					\
450 												memcpy(currentShadingState->lightingTags,tagStart,numVertices*sizeof(int));		\
451 																											\
452 												/* clear all lights */										\
453 												*freeLights 	=	*lights;								\
454 												*lights			=	NULL;									\
455 																											\
456 												if (inShadow == FALSE) {									\
457 																											\
458 													for (CActiveLight *cLight=currentAttributes->lightSources;cLight!=NULL;cLight=cLight->next) {		\
459 														CProgrammableShaderInstance	*light	=	cLight->light;							\
460 														lightCategoryCheck;																\
461 														if (light->flags & SHADERFLAGS_NONAMBIENT) {									\
462 															memBegin(shaderStateMemory);												\
463 															currentShadingState->currentLightInstance			=	light;				\
464 															currentShadingState->locals[ACCESSOR_LIGHTSOURCE]	=	light->prepare(shaderStateMemory,varying,numVertices);	\
465 															light->illuminate(this,currentShadingState->locals[ACCESSOR_LIGHTSOURCE]);										\
466 															memEnd(shaderStateMemory);						\
467 														}													\
468 													}														\
469 												}															\
470 												assert(currentShadingState->numActive	==	numActive);		\
471 												assert(currentShadingState->numPassive	==	numPassive);	\
472 																											\
473 												currentShadingState->currentShaderInstance	=	cInstance;	\
474 											}
475 
476 #define		CATEGORYLIGHT_PRE(lC)			int	runCat = 0,saveCat = 0;										\
477 											int	invertCatMatch = FALSE;										\
478 											if (*(*lC) != '\0') {											\
479 												if (*(*lC) == '-') {										\
480 													saveCat = -(runCat = CRenderer::getGlobalID(*lC+1));	\
481 													invertCatMatch = TRUE;									\
482 												} else {													\
483 													saveCat = runCat = CRenderer::getGlobalID(*lC);			\
484 												}															\
485 											}
486 
487 #define		CATEGORYLIGHT_CHECK				if (light->categories != NULL) {								\
488 												int			validLight = FALSE;								\
489 												for (const int *cCat=light->categories;(*cCat!=0);cCat++) {	\
490 													if (*cCat == runCat) {									\
491 														validLight = TRUE;									\
492 														break;												\
493 													}														\
494 												}															\
495 												if (invertCatMatch) {										\
496 													if (validLight)		continue;							\
497 												} else {													\
498 													if (!validLight)	continue;							\
499 												}															\
500 											} else if (!invertCatMatch) {									\
501 												continue;													\
502 											}
503 
504 #define		runCategoryLights(lP,lN,lT,lC)	runLightsTemplate(lP,lN,lT,CATEGORYLIGHT_PRE(lC),CATEGORYLIGHT_CHECK)
505 
506 #define		NORMALLIGHT_PRE					int saveCat = 0;
507 
508 #define		runLights(lP,lN,lT)				runLightsTemplate(lP,lN,lT,NORMALLIGHT_PRE,NULL_EXPR)
509 
510 // The misc macros
511 #define		DEFLINKOPCODE(name,text,nargs)				case OPCODE_##name:
512 #define		DEFLINKFUNC(name,text,prototype,par)		case FUNCTION_##name:
513 
514 // Break the shader execution
515 #define		BREAK							goto execEnd;
516 
517 	// Uninitialized local variables
518 	CGatherBundle		*lastGather;
519 
520 	// This is the current shader we're executing
521 	CShader		*currentShader			=	cInstance->parent;
522 
523 	assert((currentShadingState->numActive+currentShadingState->numPassive) == currentShadingState->numVertices);
524 
525 	currentShadingState->currentShaderInstance	=	cInstance;
526 	const TCode	*code					=	currentShader->codeArea + currentShader->codeEntryPoint;
527 	int			*tagStart				=	currentShadingState->tags;
528 
529 	// Save this stuff for fast access
530 	int				numVertices			=	currentShadingState->numVertices;
531 	float			**varying			=	currentShadingState->varying;
532 	CShadedLight	**lights			=	&currentShadingState->lights;
533 	CShadedLight	**alights			=	&currentShadingState->alights;
534 	CShadedLight	**currentLight		=	&currentShadingState->currentLight;
535 	CShadedLight	**freeLights		=	&currentShadingState->freeLights;
536 
537 	// Set the access arrays
538 	void	**stuff[3];
539 	stuff[SL_IMMEDIATE_OPERAND]			=	currentShader->constantEntries;				// Immediate operands
540 	stuff[SL_GLOBAL_OPERAND]			=	(void **) varying;							// Global variables
541 	stuff[SL_VARYING_OPERAND]			=	(void **) locals;							// Local variables
542 
543 	int				numActive			=	currentShadingState->numActive;
544 	int				numPassive			=	currentShadingState->numPassive;
545 	CConditional	*lastConditional	=	NULL;										// The last conditional block
546 
547 	// Execute
548 execStart:
549 	const ESlCode	opcode	=	(ESlCode)	code->opcode;	// Get the opcode
550 	int				*tags	=	tagStart;					// Set the tags to the start
551 
552 
553 #define		DEFOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params)					\
554 			case OPCODE_##name:																		\
555 			{																						\
556 				expr_pre;																			\
557                 if (code->uniform) {																\
558 					expr;																			\
559                 } else if (numPassive != 0) {                                 						\
560 					for (int currentVertex=numVertices;currentVertex>0;--currentVertex,++tags) {	\
561 						if (*tags == 0) {															\
562 							expr;																	\
563 						}																			\
564 						expr_update;																\
565 					}																				\
566 				} else {							                                                \
567 					for (int currentVertex=numVertices;currentVertex>0;--currentVertex) {			\
568 						expr;																		\
569 						expr_update;																\
570 					}																				\
571 				}																					\
572 				expr_post;																			\
573 				code++;																				\
574 				goto execStart;																		\
575 			}
576 
577 #define		DEFSHORTOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,params)				\
578 			case OPCODE_##name:																		\
579 			{																						\
580 				expr_pre;																			\
581                 if (code->uniform) {																\
582 					expr;																			\
583                 } else if (numPassive != 0) {                                 						\
584 					for (int currentVertex=currentShadingState->numRealVertices;currentVertex>0;--currentVertex,++tags) {	\
585 						if (*tags == 0) {															\
586 							expr;																	\
587 						}																			\
588 						expr_update;																\
589 					}																				\
590 				} else {							                                                \
591 					for (int currentVertex=currentShadingState->numRealVertices;currentVertex>0;--currentVertex) {			\
592 						expr;																		\
593 						expr_update;																\
594 					}																				\
595 				}																					\
596 				expr_post;																			\
597 				code++;																				\
598 				goto execStart;																		\
599 			}
600 
601 
602 #define		DEFFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par)					\
603 			case FUNCTION_##name:																	\
604 			{																						\
605 				expr_pre;																			\
606                 if (code->uniform) {																\
607 					expr;																			\
608                 } else if (numPassive != 0) {                                 						\
609 					for (int currentVertex=numVertices;currentVertex>0;--currentVertex,++tags) {	\
610 						if (*tags == 0) {															\
611 							expr;																	\
612 						}																			\
613 						expr_update;																\
614 					}																				\
615 				} else {							                                                \
616 					for (int currentVertex=numVertices;currentVertex>0;--currentVertex) {			\
617 						expr;																		\
618 						expr_update;																\
619 					}																				\
620 				}																					\
621 				expr_post;																			\
622 				code++;																				\
623 				goto execStart;																		\
624 			}
625 
626 #define		DEFLIGHTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par)				\
627 			case FUNCTION_##name:																	\
628 			{																						\
629                 if (code->uniform) {																\
630 					scripterror("Invalid uniform lighting call");									\
631                 } else {                                 											\
632 					expr_pre;																		\
633 					for (int currentVertex=numVertices;currentVertex>0;--currentVertex,++tags) {	\
634 						if (*tags == 0) {															\
635 							expr;																	\
636 						}																			\
637 						expr_update;																\
638 					}																				\
639 					expr_post;																		\
640 				}																					\
641 				code++;																				\
642 				goto execStart;																		\
643 			}
644 
645 #define		DEFSHORTFUNC(name,text,prototype,expr_pre,expr,expr_update,expr_post,par)				\
646 			case FUNCTION_##name:																	\
647 			{																						\
648 				expr_pre;																			\
649                 if (code->uniform) {																\
650 					expr;																			\
651                 } else if (numPassive != 0) {                                 						\
652 					for (int currentVertex=currentShadingState->numRealVertices;currentVertex>0;--currentVertex,++tags) {	\
653 						if (*tags == 0) {															\
654 							expr;																	\
655 						}																			\
656 						expr_update;																\
657 					}																				\
658 				} else {							                                                \
659 					for (int currentVertex=currentShadingState->numRealVertices;currentVertex>0;--currentVertex) {			\
660 						expr;																		\
661 						expr_update;																\
662 					}																				\
663 				}																					\
664 				expr_post;																			\
665 				code++;																				\
666 				goto execStart;																		\
667 			}
668 
669     switch(opcode) {
670 
671 #include "scriptOpcodes.h"
672 
673 #include "scriptFunctions.h"
674 
675     default:
676         error(CODE_BUG,"Opcode conflict in shader \"%s\"",cInstance->getName());
677         goto execEnd;
678     }
679 
680     // Resume executing instructions
681     code++;
682     goto execStart;
683 
684 #undef DEFOPCODE
685 #undef DEFSHORTOPCODE
686 #undef DEFFUNC
687 #undef DEFLIGHTFUNC
688 #undef DEFSHORTFUNC
689 
690 execEnd:
691 
692 	// Make sure we save the ambient contribution if there has been no illuminate/solar executed
693 	if (currentShader->type == SL_LIGHTSOURCE) {
694 		if (!(currentShader->usedParameters & PARAMETER_NONAMBIENT)) {
695 			const float	*Cl		=	varying[VARIABLE_CL];
696 			float		*Clsave;
697 
698 			// Save the ambient junk
699 			Clsave	= (*alights)->savedState[1];
700 			tags	= tagStart;
701 			for (int i=numVertices;i>0;--i,Cl+=3,Clsave+=3,++tags) {
702 				if (*tags==0) {
703 					addvv(Clsave,Cl);
704 				}
705 			}
706 		}
707 	}
708 
709 // Undefine junk
710 #undef		savestring
711 #undef		allocbuffer
712 #undef		freebuffer
713 #undef		beginConditional
714 #undef		endConditional
715 #undef		operand
716 #undef		parameterlist
717 #undef		argument
718 #undef		argumentcount
719 #undef		jmp
720 #undef		runAmbientLights
721 #undef		runLightsTemplate
722 #undef		CATEGORYLIGHT_PRE
723 #undef		CATEGORYLIGHT_CHECK
724 #undef		runCategoryLights
725 #undef		NORMALLIGHT_PRE
726 #undef		runLights
727 #undef		firstLight
728 #undef		nextLight
729 #undef		allLights
730 #undef		currentLight
731 #undef		saveLight
732 #undef		uniformGlobal
733 #undef		varyingGlobal
734 #undef		DEFOPCODE
735 #undef		DEFFUNC
736 #undef		DEFLINKOPCODE
737 #undef		DEFLINKFUNC
738 #undef		BREAK
739 }
740 
741