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 = ¤tShadingState->lights;
533 CShadedLight **alights = ¤tShadingState->alights;
534 CShadedLight **currentLight = ¤tShadingState->currentLight;
535 CShadedLight **freeLights = ¤tShadingState->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