1 /* 2 Copyright (c) 2008 Seneca College 3 Licenced under the MIT License (http://www.c3dl.org/index.php/mit-license/) 4 */ 5 6 /** 7 @class 8 9 <p>An EffectTemplate is a template for creating many Effects which have 10 similar rendering results. Effects instantiated from EffectTemplates 11 achieve different rendering results by changing the parameters of the 12 EffectTemplate.</p> 13 14 <p>Effects cannot instantiate EffectTemplates until the EffectTemplate has been 15 initialized. However, once initialized, the EffectTemplate can no longer be modified. 16 This includes changing the callback, parameters, shaders, etc.</p> 17 18 <p>When an effect is instantiated from an effect template, any parameters the effect template 19 has which are do not have default values must be set before the object with the effect is rendered.</p> 20 */ 21 c3dl.EffectTemplate = function() 22 { 23 this.vertexShaders = []; 24 this.fragmentShaders = []; 25 this.isInitialized = false; 26 27 // array of objects. 28 this.params = []; 29 this.renderingCB = null; 30 31 // 32 // 33 this.programObjects = []; 34 35 36 /** 37 Call this once the vertex shader, fragment shader and rendering callback have been 38 set and all parameters have been created. Once the EffectTemplate has been initialized, 39 neither the shaders, callback or parameters can be changed. 40 41 @returns {bool} true if the EffectTemplate was initialized, false otherwise. 42 */ 43 this.init = function() 44 { 45 var rc = false; 46 47 // can only be initialize once 48 if( this.isInitialized == false) 49 { 50 // these variables had to be set, parameters variable 51 // is optional. 52 if( this.renderingCB && this.vertexShaders.length > 0 && 53 this.fragmentShaders.length > 0) 54 { 55 this.isInitialized = true; 56 rc = true; 57 } 58 } 59 return rc; 60 } 61 62 /** 63 Adds a fragment shader to the list of fragment shaders which need to be compiled. 64 The fragment shader strings are literally added together, therefore the order 65 which they are added is important. For example, if the material struct it used, 66 the variable holding the material string code should be added before the light 67 string code since the light code depends on material code. 68 69 @param {String} fragmentShader 70 */ 71 this.addFragmentShader = function(fragmentShader) 72 { 73 if(this.isInitialized == false) 74 { 75 if(fragmentShader && typeof(fragmentShader) == "string") 76 { 77 this.fragmentShaders.push(fragmentShader); 78 } 79 else 80 { 81 c3dl.debug.logWarning("Invalid argument passed to Effect's addFragmentShader()."); 82 } 83 } 84 } 85 86 /** 87 Add a parameter which and instance effect can modify. Parameters should be simple, built-in 88 types such as Boolean, Number, Array etc. They should not be Objects created with {}. 89 90 @param {String} paramName 91 @param paramType Constructor used to create the object such as Boolean, Number, Array, etc. 92 @param paramDefaultValue The default value to be used if the user 93 does not specify any value. If null, user will have to specify a value, 94 otherwise the object with this effect will not be rendered. 95 */ 96 this.addParameter = function(paramName, paramType, paramDefaultValue) 97 { 98 if(this.isInitialized == false) 99 { 100 if(paramName && typeof(paramName) == "string") 101 { 102 var val; 103 104 if(paramType == Array) 105 { 106 val = c3dl.copyObj(paramDefaultValue); 107 } 108 else 109 { 110 val = paramDefaultValue; 111 } 112 113 // Each parameter will be an object, so when copying is done 114 // we can iterate the list by simply incrementing by one. 115 this.params.push({name:paramName, type:paramType, value:val}); 116 } 117 else 118 { 119 c3dl.debug.logWarning("Invalid argument(s) passed to Effect's addParameter()."); 120 } 121 } 122 else 123 { 124 c3dl.debug.logWarning("Effect addParameter(): cannot be called once an effect has been initialized."); 125 } 126 } 127 128 /** 129 Adds a vertex shader to the list of vertex shaders which need to be compiled. 130 The vertex shader strings are literally added together, therefore the order 131 which they are added is important. For example, if the material struct it used, 132 the variable holding the material string code should be added before the light 133 string code since the light code depends on material code. 134 135 @param {String} vertexShader 136 */ 137 this.addVertexShader = function(vertexShader) 138 { 139 if(this.isInitialized == false) 140 { 141 if(vertexShader && typeof(vertexShader) == "string") 142 { 143 this.vertexShaders.push(vertexShader); 144 } 145 else 146 { 147 c3dl.debug.logWarning("Invalid argument passed to Effect's addVertexShader()."); 148 } 149 } 150 } 151 152 /** 153 @private 154 Renderer will call this when it needs to compile the vertex shaders. 155 156 @returns {String[]} vertex shaders. 157 */ 158 this.getVertexShaders = function() 159 { 160 return this.vertexShaders; 161 } 162 163 /** 164 @private 165 166 Get the array of all the parameters of this effect template. 167 168 @returns {Array} array of objects. 169 */ 170 this.getParameters = function() 171 { 172 var ret = []; 173 174 for(var i =0; i < this.params.length; i++) 175 { 176 var val; 177 178 if(typeof this.params[i].value == "Array") 179 { 180 val = c3dl.copyObj(this.params[i].value); 181 } 182 else 183 { 184 val = this.params[i].value; 185 } 186 187 ret.push( 188 {name:this.params[i].name, 189 type:this.params[i].type, 190 value:val} 191 ); 192 } 193 194 return ret; 195 } 196 197 /** 198 @private 199 200 Renderer will call this when it needs to compile the fragment shaders. 201 202 @returns {String[]} fragment shaders 203 */ 204 this.getFragmentShaders = function() 205 { 206 return this.fragmentShaders; 207 } 208 209 /** 210 Get the callback which is to be called when the 211 geometric object with an effect created from this effect template is rendered. 212 213 @returns {Function} The function which will render the geometric object 214 with an effect created from this template effect. 215 */ 216 this.getRenderingCallback = function() 217 { 218 return this.renderingCB; 219 } 220 221 /** 222 Set the rendering callback which will be called by the renderer when the 223 object with this effect needs to be rendered. The renderer will pass a 224 renderingObject to the function which can be queried for context, renderer, 225 effect, etc. 226 227 @see c3dl.RenderingObject. 228 229 @param {Function} func 230 */ 231 this.setRenderingCallback = function(func) 232 { 233 if(this.isInitialized == false) 234 { 235 if(func instanceof Function) 236 { 237 this.renderingCB = func; 238 } 239 else 240 { 241 c3dl.debug.logWarning("Invalid argument passed to Effect's setRenderingCB()."); 242 } 243 } 244 } 245 246 /** 247 @private 248 249 When the renderer compiles the shaders, it returns a program object id. Each 250 renderer will have its own id for this particular effect. 251 252 @returns {int} -1 if the rendererID was not found in the list 253 */ 254 this.getProgramID = function(rendererID) 255 { 256 var programID = -1; 257 var found = false; 258 259 for(var i = 0; found == false && i < this.programObjects.length; i++) 260 { 261 if(found === false) 262 { 263 if( rendererID == this.programObjects[i].getRendererID()) 264 { 265 found = true; 266 programID = this.programObjects[i].getProgramID(); 267 } 268 } 269 } 270 return programID; 271 } 272 273 /** 274 @private 275 276 @param {c3dl.ProgramObject} programObject 277 */ 278 this.addProgramObject = function(programObject) 279 { 280 this.programObjects.push(programObject); 281 } 282 283 /** 284 Get a string representation of this object. 285 286 @param {String} [delimiter=","] A string which will separate values. 287 */ 288 this.toString = function(delimiter) 289 { 290 if(!delimiter && typeof(delimiter) != "string") 291 { 292 delimiter = ","; 293 } 294 295 return "Initialized = " + this.isInitialized + delimiter + 296 "Vertex Shaders = " + this.vertexShaders + delimiter + 297 "Fragment Shaders = " + this.fragmentShaders + delimiter + 298 "Rendering Callback = " + this.renderingCB + delimiter + 299 "Parameters = " + this.parameters; 300 } 301 } 302