////////////////////////////////////////////////////////////////////// // // 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 : init.cpp // Classes : - // Description : This file implements the shading language interpreter that runs the init code // //////////////////////////////////////////////////////////////////////// #include #include "renderer.h" #include "shader.h" #include "slcode.h" #include "noise.h" #include "shading.h" #include "stats.h" #include "memory.h" #include "output.h" #include "error.h" //////////////////////////////////////////////////////////////////////////////////////////////// // Prototypes for shading language functions // These functions are defined in interpreter.cpp //////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// // Shading language functions ... (implemented in interpreter.cpp) CShaderCache *newCache(CShader *,CShaderCache *c=NULL); // Allocate a new cache #define saveLighting(a) scripterror("Invalid environment function call during init\n") #define clearLighting() scripterror("Invalid environment function call during init\n") #define enterLightingConditional() scripterror("Invalid environment function call during init\n") #define exitLightingConditional() scripterror("Invalid environment function call during init\n") #define enterFastLightingConditional() scripterror("Invalid environment function call during init\n") #define exitFastLightingConditional() scripterror("Invalid environment function call during init\n") #define rendererInfo(a,b) scripterror("Invalid environment function call during init\n") #define emission(a,b) scripterror("Invalid environment function call during init\n") #define clipMin 0 #define clipMax 1 #define debugFunction(a) #define illuminateBegin(a,b,c,d,e,f) /////////////////////////////////////////////////////////////////////// // Class : CShadingContext // Method : convertColorFrom // Description : Do color conversion // Return Value : - // Comments : // Date last edited : 8/25/2002 void convertColorFrom(float *out,const float *in,ECoordinateSystem s) { switch(s) { case COLOR_RGB: movvv(out,in); break; case COLOR_HSL: { #define HueToRGB(r,m1,m2,h ) \ if (h<0) h+=1; \ if (h>1) h-=1; \ if (6.0*h < 1 ) r = (m1+(m2-m1)*h*6); \ else if (2.0*h < 1 ) r = m2; \ else if (3.0*h < 2.0) r = (m1+(m2-m1)*((2.0f/3.0f)-h)*6); \ else r = m1; float m1,m2,h; if (in[1]==0) initv(out,in[2],in[2],in[2]); else { if (in[2] <=0.5) m2 = in[2]*(1+in[1]); else m2 = in[2]+in[1]-in[2]*in[1]; m1 = 2*in[2]-m2; h = in[0] + (1.0f/3.0f); HueToRGB(out[0],m1,m2,h); h = in[0]; HueToRGB(out[1],m1,m2,h); h = in[0] - (1.0f/3.0f); HueToRGB(out[2],m1,m2,h); } #undef HueToRGB } break; case COLOR_HSV: { if (in[1] < -1 || in[1] > 1) { if (in[0] == 0) { out[0] = in[2]; out[1] = in[2]; out[2] = in[2]; } else { out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; } } else { float f,p,q,t,h; int i; h = (float) fmod(in[0],1); if (h < 0) h += 1; h *= 6; i = (int) floor(h); f = h - i; p = in[2]*(1-in[1]); q = in[2]*(1-(in[1]*f)); t = in[2]*(1-(in[1]*(1-f))); switch(i) { case 0: out[COMP_R] = in[2]; out[COMP_G] = t; out[COMP_B] = p; break; case 1: out[COMP_R] = q; out[COMP_G] = in[2]; out[COMP_B] = p; break; case 2: out[COMP_R] = p; out[COMP_G] = in[2]; out[COMP_B] = t; break; case 3: out[COMP_R] = p; out[COMP_G] = q; out[COMP_B] = in[2]; break; case 4: out[COMP_R] = t; out[COMP_G] = p; out[COMP_B] = in[2]; break; case 5: out[COMP_R] = in[2]; out[COMP_G] = p; out[COMP_B] = q; break; } } } break; case COLOR_XYZ: out[COMP_R] = (float) (3.24079*in[0] - 1.537150*in[1] - 0.498535*in[2]); out[COMP_G] = (float) (-0.969256*in[0] + 1.875992*in[1] + 0.041556*in[2]); out[COMP_B] = (float) (0.055648*in[0] - 0.204043*in[1] + 1.057311*in[2]); break; case COLOR_CIE: out[COMP_R] = (float) (3.24079*in[0] - 1.537150*in[1] - 0.498535*in[2]); out[COMP_G] = (float) (-0.969256*in[0] + 1.875992*in[1] + 0.041556*in[2]); out[COMP_B] = (float) (0.055648*in[0] - 0.204043*in[1] + 1.057311*in[2]); break; case COLOR_YIQ: out[COMP_R] = (float) (in[0] + 0.956*in[1] + 0.620*in[2]); out[COMP_G] = (float) (in[0] - 0.272*in[1] - 0.647*in[2]); out[COMP_B] = (float) (in[0] - 1.108*in[1] + 1.705*in[2]); break; case COLOR_XYY: vector tin; if (in[2] == 0) { tin[0] = 0; tin[1] = 0; tin[2] = 0; } else { tin[0] = max(in[0]*in[2]/in[1],0); tin[1] = in[2]; tin[2] = max((1-in[0]-in[1])*in[2]/in[1],0); } out[COMP_R] = (float) (3.24079*tin[0] - 1.537150*tin[1] - 0.498535*tin[2]); out[COMP_G] = (float) (-0.969256*tin[0] + 1.875992*tin[1] + 0.041556*tin[2]); out[COMP_B] = (float) (0.055648*tin[0] - 0.204043*tin[1] + 1.057311*tin[2]); break; default: break; } } /////////////////////////////////////////////////////////////////////// // Class : CShadingContext // Method : convertColorTo // Description : Do color conversion // Return Value : - // Comments : // Date last edited : 8/25/2002 void convertColorTo(float *out,const float *in,ECoordinateSystem s) { switch(s) { case COLOR_RGB: movvv(out,in); break; case COLOR_HSL: { float mi = min(in[0],min(in[1],in[2])); float ma = max(in[0],max(in[1],in[2])); out[2] = (mi + ma) / 2; if (ma == mi) { out[0] = 100;// install value out of -1 to 1 range out[1] = 0; } else { float d = ma - mi; if (out[2] < 0.5) { out[1] = d / (ma + mi); } else { out[1] = d / (2 - (ma + mi)); } if (in[COMP_R] == ma) { out[0] = (in[COMP_G] - in[COMP_B])/d; } else if (in[COMP_G] == ma) { out[0] = 2 + (in[COMP_B] - in[COMP_R])/d; } else { out[0] = 4 + (in[COMP_R] - in[COMP_G])/d; } out[0] /= (float) 6; if (out[0] < 0) out[0] += 1; } } break; case COLOR_HSV: { float ma = max(in[0],max(in[1],in[2])); float mi = min(in[0],min(in[1],in[2])); out[2] = ma; out[1] = (ma - mi) / ma; if (ma == 0) { out[0] = 100;// install value out of -1 to 1 range } else { float d = ma - mi; if (in[COMP_R] == ma) { out[0] = (in[COMP_G] - in[COMP_B]) / d; } else if (in[COMP_G] == ma) { out[0] = 2 + (in[COMP_B] - in[COMP_R]) / d; } else { out[0] = 4 + (in[COMP_R] - in[COMP_G]) / d; } out[0] /= (float) 6; if (out[0] < 0) out[0] += 1; } } break; case COLOR_XYZ: out[0] = (float) (0.412453 * in[COMP_R] + 0.357580 * in[COMP_G] + 0.180423 * in[COMP_B]); out[1] = (float) (0.212671 * in[COMP_R] + 0.715160 * in[COMP_G] + 0.072169 * in[COMP_B]); out[2] = (float) (0.019334 * in[COMP_R] + 0.119193 * in[COMP_G] + 0.950227 * in[COMP_B]); break; case COLOR_CIE: out[0] = (float) (0.412453 * in[COMP_R] + 0.357580 * in[COMP_G] + 0.180423 * in[COMP_B]); out[1] = (float) (0.212671 * in[COMP_R] + 0.715160 * in[COMP_G] + 0.072169 * in[COMP_B]); out[2] = (float) (0.019334 * in[COMP_R] + 0.119193 * in[COMP_G] + 0.950227 * in[COMP_B]); break; case COLOR_YIQ: out[0] = (float) (0.299 * in[COMP_R] + 0.587 * in[COMP_G] + 0.114 * in[COMP_B]); out[1] = (float) (0.596 * in[COMP_R] - 0.275 * in[COMP_G] - 0.321 * in[COMP_B]); out[2] = (float) (0.212 * in[COMP_R] - 0.523 * in[COMP_G] + 0.311 * in[COMP_B]); break; case COLOR_XYY: vector tin; float sum; tin[0] = (float) (0.412453 * in[COMP_R] + 0.357580 * in[COMP_G] + 0.180423 * in[COMP_B]); tin[1] = (float) (0.212671 * in[COMP_R] + 0.715160 * in[COMP_G] + 0.072169 * in[COMP_B]); tin[2] = (float) (0.019334 * in[COMP_R] + 0.119193 * in[COMP_G] + 0.950227 * in[COMP_B]); sum = tin[0] + tin[1] + tin[2]; if (sum == 0) { initv(out,0,0,0); } else { out[0] = tin[0] / sum; out[1] = tin[1] / sum; out[2] = tin[2]; } break; default: break; } } /////////////////////////////////////////////////////////////////////// // Function : sfInit // Description : Execute the current shader's init code // Return Value : - // Comments : // Date last edited : 11/28/2001 void CRendererContext::init(CProgrammableShaderInstance *currentShaderInstance) { // 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); \ currentShaderInstance->parent->codeEntryPoint = -1; \ currentShaderInstance->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 = new 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 an integer operand (label references are integer) #define argument(i) code[IP+i+2].integer; // Retrieve the number of arguments #define argumentcount(n) n = code[IP+1].arguments.numArguments; // Control transfer #define jmp(n) { \ IP = n; \ goto execStart; \ } // Run the light source shaders for the lP #define runAmbientLights() scripterror("Light source exec during init code\n"); // Run the light source shaders for the lP #define runLights(lP,lN,lT) scripterror("Light source exec during init code\n"); #define runCategoryLights(lP,lN,lT,lC) scripterror("Light source exec during init code\n"); // 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; int numPassive; int *tags; int *tagStart; int currentVertex = 0; CShader *currentShader = currentShaderInstance->parent; TCode *code; int tmpTags; int numVertices; float **varying; CShadedLight **lights; CShadedLight **alights; CShadedLight **currentLight; CShaderCache *cCache; CConditional *conditionals = NULL; CConditional *cConditional; int i; code = currentShader->codeArea; IP = currentShader->initEntryPoint; numVertices = 1; tagStart = &tmpTags; tmpTags = 0; // Allocate the needed memory TCode *sb = (TCode *) ralloc((numVertices*currentShader->totalVaryingSize + currentShader->totalUniformSize + currentShader->numVariables + currentShader->numUniforms)*sizeof(TCode)); // Set the access arrays stuff[SL_VARYING_OPERAND] = (TCode **) sb; // Shader varying variables sb += currentShader->numVariables; stuff[SL_UNIFORM_OPERAND] = (TCode **) sb; // Shader uniform variables sb += currentShader->numUniforms; for (i=0;inumVariables;i++) { // Allocate memory for every varying variable stuff[SL_VARYING_OPERAND][i] = sb; sb += currentShader->varyingSizes[i]*numVertices; } for (i=0;inumUniforms;i++) { // Allocate memory for every uniform variable stuff[SL_UNIFORM_OPERAND][i] = sb; sb += currentShader->uniformSizes[i]; } varying = NULL; lights = NULL; alights = NULL; currentLight = NULL; cCache = NULL; // Set the access arrays stuff[SL_IMMEDIATE_OPERAND] = currentShader->constantEntries; // Immediate operands stuff[SL_PARAMETER_OPERAND] = currentShaderInstance->parameterEntries; // Parameters stuff[SL_GLOBAL_OPERAND] = (TCode **) varying; // Varying globals numActive = numVertices; numPassive = 0; lastConditional = NULL; // The last conditional block // Execute execStart: opcode = (ESlCode) code[IP].integer; tags = tagStart; #define INIT_SHADING #define DEFOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,param) \ case OPCODE_##name: \ { \ expr_pre; \ expr; \ expr_post \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } \ break; #define DEFSHORTOPCODE(name,text,nargs,expr_pre,expr,expr_update,expr_post,param) \ case OPCODE_##name: \ { \ expr_pre; \ expr; \ expr_post \ IP += code[IP+1].arguments.numCodes; \ goto execStart; \ } \ break; #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; \ } \ break; #define DEFLIGHTFUNC(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; \ } \ break; #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; \ } \ break; switch(opcode) { #include "scriptOpcodes.h" #include "scriptFunctions.h" default: goto execEnd; } IP += code[IP+1].arguments.numCodes; goto execStart; #undef DEFOPCODE #undef DEFFUNC #undef DEFLIGHTFUNC #undef INIT_SHADING goto execStart; execEnd: // Delete the conditionals while((cConditional=conditionals) != NULL) { conditionals = cConditional->next; delete cConditional; } assert(numActive == numVertices); assert(numPassive == 0); // Undefine junk #undef MAX_SCRIPT_STRING_SIZE #undef savestring #undef allocbuffer #undef freebuffer #undef beginConditional #undef endConditional #undef operand #undef argument #undef argumentcount #undef jmp #undef runAmbientLights #undef runCategoryLights #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 }