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 WebGL context.
  8 	@augments c3dl.Renderer
  9 */
 10 c3dl.WebGL = function()
 11 {  
 12 	var glCanvas3D = null; // GL Context; 
 13 	this.texManager = null;
 14 	
 15 	// overwrite the version set in the Renderer base class.
 16 	this.version = 2.0;
 17 	
 18 	// overwrite the version set in the Renderer base class.
 19 	this.versionString = "WebGL";
 20 
 21 	// program objects to render various visual objects.
 22 	this.geometryShader;
 23 	this.particleSystemShader;
 24 	this.pointShader;
 25 	this.pointSphereShader;
 26 	this.lineShader;
 27 	this.boundingSphereShader;
 28 	this.programsWithLights = [];
 29 	
 30 	/// Maybe need to move these out somewhere else
 31 	this.pointVertBuffer = null;
 32 	this.pointColBuffer = null;
 33 	
 34 	this.lineVertBuffer = null;
 35 	this.lineColBuffer = null;
 36 	
 37 	// unique id of this renderer
 38 	this.ID = c3dl.getNextRendererID();
 39 	this.STANDARD_PROGRAM_ID = null;
 40 	
 41 	this.textureQueue = [];
 42   
 43   // have the vbos to render point spheres been created
 44   this.pointSphereRenderReady = false;
 45   
 46   // Verts, Normals, etc will be added to this.
 47   this.pointsphereVBOVert;
 48 
 49 	/**
 50 		Add a texture to the renderer. If the texture was added before
 51 		the renderer was initialized, the texture will be placed in a 
 52 		queue and the texture will be created once the renderer has been
 53 		initialized.
 54 		
 55 		The renderer will create an internal ID for the texture which can
 56 		be queried by calling getTextureID. This ID can be passed to commands 
 57 		of the context in the rendering callback function in effects to make 
 58 		that texture active.
 59 		
 60 		@parma {String} path Texture path
 61 	*/
 62 	this.addTexture = function(path)
 63 	{
 64 		//
 65 		if(this.texManager == null)
 66 		{
 67 			this.textureQueue.push(path);
 68 		}
 69 		else
 70 		{
 71 			this.texManager.addTexture(path);
 72 		}
 73 	}
 74 	
 75 	/**
 76 		Get the unique ID of this renderer.
 77 		
 78 		@returns {int} unique ID of this renderer.
 79 	*/
 80 	this.getID = function()
 81 	{
 82 		return this.ID;
 83 	}
 84 	
 85 	/**
 86 		Get the ID of the texture at 'texturePath'. If the texture could not
 87 		be found or the renderer has not yet been initialized, -1 will be 
 88 		returned.
 89 
 90 		@param {String} texturePath
 91 		
 92 		@returns {int} The ID of the texture, or -1 if the renderer has not 
 93 		yet been initialized or if the texture was not found.
 94 	*/
 95 	this.getTextureID = function(texturePath)
 96 	{
 97 		if(this.texManager)
 98 		{
 99 			return this.texManager.getID(texturePath);
100 		}
101 		else
102 		{
103 			return -1;
104 		}
105 	}
106 
107 	/**
108 		@private
109 		Is the renderer ready?
110 
111 		@returns {boolean} True if the context is not null, otherwise false.
112 	*/
113 	this.isReady = function()
114 	{
115 		return glCanvas3D == null ? false : true; 
116 	}
117 
118 	/**
119 		Get the OpenGL context.
120 
121 		@returns {Context} The GL Context.
122 	*/
123 	this.getGLContext = function()
124 	{
125 		return glCanvas3D;
126 	}
127 
128 	/**
129 		@private
130 		Create a program which is composed of shaders.
131 		
132 		Create a program object which is composed of compiled shader objects.
133 		This program object can be installed as the current rendering state 
134 		by using gl.useProgram().
135 
136 		@param {Array|String} vertexShaderSource The source code for the vertex shader.
137 		@param {Array|String} fragmentShaderSource The source code for the fragment shader.
138 		
139 		@return {c3dl.ProgramObject} ProgramObject or null .
140 	*/
141 	this.createProgram = function(vertexShader, fragmentShader)
142 	{
143 		// We don't check the parameters because the openGL functions will already
144 		// be checking to make sure the source is valid when it compiles them. If 
145 		// they are invalid, error messages will be displayed on the page.
146 		
147 		// make alias for shorter code.
148 		var gl = glCanvas3D;
149 
150 		// createProgram creates a program object to which our shaders can be
151 		// attached. We can later tell openGL which program to use by 
152 		// calling useProgram().
153 		var program = gl.createProgram();
154 		
155 		// it is possible createProgram failed.
156 		if (program == null)
157 		{
158 			c3dl.debug.logError("failed to create shader program");
159 			return null;
160 		}
161 	
162 		var vertShader = gl.createShader(gl.VERTEX_SHADER);
163 		gl.shaderSource(vertShader, vertexShader);
164 		
165 		
166 		gl.compileShader(vertShader);
167 		
168 		// The compilation status of each shader can be queried.
169 		if (!gl.getShaderParameter(vertShader, gl.COMPILE_STATUS))
170 		{
171 			c3dl.debug.logError("vert shader: " + gl.getShaderInfoLog(vertShader));
172 			gl.deleteShader(vertShader);
173 			return null;
174 		}
175 		
176 		gl.attachShader(program, vertShader);
177 			
178 
179 		var vertShader = gl.createShader(gl.FRAGMENT_SHADER);
180 		gl.shaderSource(vertShader, fragmentShader);
181 		gl.compileShader(vertShader);
182 		
183 		// The compilation status of each shader can be queried.
184 		if (!gl.getShaderParameter(vertShader, gl.COMPILE_STATUS))
185 		{
186 			c3dl.debug.logError("frag shader " +gl.getShaderInfoLog(vertShader));
187 			gl.deleteShader(vertShader);
188 			return null;
189 		}
190 		gl.attachShader(program, vertShader);
191 		
192 		// Linking is the final step which must be done to obtain a valid
193 		// program object. Linking assigns variable locations for uniform variables,
194 		// initialized user-defined uniform variables, resolves references
195 		// between independently compiled shader objects, etc.
196 		//
197 		// The status of the link operation is stored as part of the program object's
198 		// state which we will query.
199 		// 
200 		gl.linkProgram(program);
201 
202 		// Check if the shaders were linked successfully.
203 		if (gl.getProgramParameter(program, gl.LINK_STATUS) != 1)
204 		{
205 			c3dl.debug.logError(gl.getProgramInfoLog(program));
206 			gl.deleteProgram(program);
207 			return null;
208 		}
209 
210 		// create a program object, similar to an opengl program object.
211 		var programObject = new c3dl.ProgramObject();
212 		programObject.rendererID = this.ID;
213 		programObject.programID = program;
214 	
215 		return programObject;
216 	}
217 		
218 	/**
219 		@private
220 		Clear the color and depth buffers.
221 		
222 		Scene is responsible for calling this.
223 	*/
224 	this.clearBuffers = function()
225 	{
226 		glCanvas3D.clear(glCanvas3D.COLOR_BUFFER_BIT | glCanvas3D.DEPTH_BUFFER_BIT);
227 	}
228 		
229 	/**
230 		@private
231 		Swap the front and back buffers. Scene is responsible for calling this.
232 	*/
233 	this.swapBuffers = function()
234 	{
235 		glCanvas3D.clear(glCanvas3D.COLOR_BUFFER_BIT | glCanvas3D.DEPTH_BUFFER_BIT);
236 	}
237 	
238 	/**
239 		@private
240 		this is documented in the renderer class
241 	*/
242 	this.setClearColor = function(bgColor)
243 	{	
244 		if( bgColor.length >= 3 )
245 		{
246 			glCanvas3D.clearColor(bgColor[0],bgColor[1],bgColor[2],1.0);
247 		}
248 	}
249 
250 	/**
251 		@private
252 		
253 		implementes the 'virtual' function getMaxLineWidth from renderer.
254 		
255 		Get the maximum line width supported which is implementation
256 		dependent.
257 		
258 		@returns {int} maximum line width supported.
259 	*/
260 	this.getMaxLineWidth = function()
261 	{
262 		// returns the range, first value represents minimum value supported.
263 		// opengles guarantees support for width of 1.
264 		
265 		// should this be checked once on init and then we don't have to keep querying?
266 		var maxLineWidth = glCanvas3D.getParameter(glCanvas3D.ALIASED_LINE_WIDTH_RANGE);
267 		
268 		return maxLineWidth[1];
269 	}
270 	
271 	/**
272 		@private
273 		Set the shader values to zero so the light no longer affects the scene.
274 		
275 		@param {int} lightID The light to clear must range from 0 to one less than c3dl.MAX_LIGHTS.
276 	*/
277 	this.clearLight = function(lightID)
278 	{
279 		if(lightID >= 0 && lightID < c3dl.MAX_LIGHTS)
280 		{
281 			for(var i = 0; i < this.programsWithLights.length; i++)
282 			{
283 				var PID = this.programsWithLights[i];
284 				
285 				// base string to shorten code below.
286 				var base = "lights[" + lightID + "].";
287 
288 				glCanvas3D.useProgram(PID);
289 				this.setUniformf(PID, base + "position", [0,0,0]);
290 				this.setUniformf(PID, base + "ambient", [0,0,0]);
291 				this.setUniformf(PID, base + "diffuse", [0,0,0]);
292 				this.setUniformf(PID, base + "specular", [0,0,0]);
293 				this.setUniformf(PID, base + "spotDirection", [0,0,-1]);
294 				this.setUniformf(PID, base + "spotCutoff", 180);
295 				this.setUniformf(PID, base + "spotExponent", 0);
296 				this.setUniformf(PID, base + "attenuation1", 1);
297 				this.setUniformf(PID, base + "attenuation2", 0);
298 				this.setUniformf(PID, base + "attenuation3", 0);
299 				this.setUniformi(PID, base + "type", 0);
300 				this.setUniformi(PID, base + "isOn", 0);
301 			}
302 		}
303 	}
304 	
305 	/**
306 		@private
307 		
308 		@param {Array} ambientLight Array of lights
309 	*/
310 	this.updateAmbientLight = function(ambientLight)
311 	{
312 		// the toon shader uses lights, but does not use
313 		// the ambient light. We need to turn off debugger to
314 		// suppress any errors.
315 		var prevVal = c3dl.debug.getVisible();
316 		c3dl.debug.setVisible(false);
317 
318 		for(var i = 0; i < this.programsWithLights.length; i++)
319 		{
320 			glCanvas3D.useProgram(this.programsWithLights[i]);		
321 			this.setUniformf(this.programsWithLights[i], "ambientLightColor", ambientLight);
322 			this.setUniformi(this.programsWithLights[i], "lightingOn", this.getLighting());
323 		}
324 		
325 		// turn it back on if it was on before.
326 		if(prevVal == true)
327 		{
328 			c3dl.debug.setVisible(true);
329 		}
330 	}
331 	
332 	/**
333 		@private
334 		Update the light states in the shader with lightList.
335 		
336 		@param {Array} lightList Array of lights
337 	*/
338 	this.updateLights = function(lightList)
339 	{
340 		// The list of all the program objects which have lights need to be updated
341 		for(var progObjIter = 0; progObjIter < this.programsWithLights.length; progObjIter++)
342 		{
343 			var shader = this.programsWithLights[progObjIter];
344 
345 			glCanvas3D.useProgram(shader);
346 
347 			// iterate over all the lights
348 			for(var i = 0 ; i < lightList.length; i++)
349 			{
350 				// create a base string to shorten code below.
351 				var base = "lights[" + i + "].";
352 
353 				// we may have nulls in the array which represent places lights can be inserted
354 				// so we have to check for these.
355 				if(lightList[i] != null)
356 				{
357 					// if the light is off, that's the only uniform var that needs to be set.
358 					if(lightList[i].isOn() == false)
359 					{
360 						this.setUniformi(shader, base + "isOn", lightList[i].isOn());
361 					}
362 					else
363 					{
364 						if(lightList[i] instanceof c3dl.DirectionalLight)
365 						{					
366 							// place the light in viewspace here instead of the shader, preventing placing the lights
367 							// in viewspace for every vertex.
368 							var dir = c3dl.multiplyMatrixByDirection(c3dl.peekMatrix(),lightList[i].getDirection());
369 							dir.push(0);
370 							
371 							this.setUniformf(shader, base + "position", dir);
372 							
373 							// this is used to distinguish a directional light from a spotlight.
374 							this.setUniformf(shader, base + "spotCutoff", 180);
375 						}
376 
377 						// check if its a spotlight first before positional light!
378 						else if(lightList[i] instanceof c3dl.SpotLight)
379 						{
380 							var pos = lightList[i].getPosition();
381 							pos = c3dl.multiplyMatrixByVector(c3dl.peekMatrix(), pos);
382 							pos.push(1);
383 							
384 							var dir = lightList[i].getDirection();
385 							dir = c3dl.multiplyMatrixByDirection(c3dl.peekMatrix(), dir);
386 
387 							this.setUniformf(shader, base + "position", pos);
388 							this.setUniformf(shader, base + "spotDirection", dir);
389 							this.setUniformf(shader, base + "spotCutoff", lightList[i].getCutoff());
390 							this.setUniformf(shader, base + "spotExponent", lightList[i].getExponent());
391 						}
392 
393 						else if(lightList[i] instanceof c3dl.PositionalLight)
394 						{
395 							var pos = lightList[i].getPosition();
396 							//pos = c3dl.multiplyMatrixByVector(c3dl.getUniform("viewMatrix"), pos);
397 							pos = c3dl.multiplyMatrixByVector(c3dl.peekMatrix(), pos);
398 							pos.push(1);
399 							
400 							this.setUniformf(shader, base + "position", pos);
401 							this.setUniformf(shader, base + "spotCutoff", 180.0);
402 						}
403 
404 						this.setUniformi(shader, base + "type", lightList[i].getType());
405 						this.setUniformi(shader, base + "isOn", lightList[i].isOn());
406 						this.setUniformf(shader, base + "ambient", lightList[i].getAmbient());
407 						this.setUniformf(shader, base + "diffuse", lightList[i].getDiffuse());
408 						this.setUniformf(shader, base + "specular", lightList[i].getSpecular());
409 						
410 						// lights are attenuated as long as they are not directional lights
411 						if(!(lightList[i] instanceof c3dl.DirectionalLight))
412 						{
413 							var attn = lightList[i].getAttenuation();
414 							this.setUniformf(shader, base + "attenuation1", attn[0]);
415 							this.setUniformf(shader, base + "attenuation2", attn[1]);
416 							this.setUniformf(shader, base + "attenuation3", attn[2]);
417 						}
418 					}
419 				}
420 			}
421 		}
422 	}
423 
424 	/*
425 
426   */
427   this.pointSphereRenderSetup = function()
428   {
429     // create the empty WebGL VBO's
430     this.pointSphereVBOVert = glCanvas3D.createBuffer();
431     
432     // bind to the VBO
433     glCanvas3D.bindBuffer(glCanvas3D.ARRAY_BUFFER,this.pointSphereVBOVert); 
434 
435     // set the data using the bounding sphere verts since that sphere has a size of 1 unit
436     glCanvas3D.bufferData(glCanvas3D.ARRAY_BUFFER, new WebGLFloatArray(c3dl.BOUNDING_SPHERE_VERTICES),glCanvas3D.STATIC_DRAW);
437     
438     // next frame we'll be ready to render
439     this.pointSphereRenderReady = true;
440   }
441   
442 	/**
443 		@private
444 		
445 		Create a Renderer.
446 
447 		@param cvs
448 
449 		@returns {boolean} True if the context could be created, 
450 		otherwise false.
451 	*/
452 	this.createRenderer = function(cvs)
453 	{
454 		if (c3dl.debug.DUMMY)
455 		{
456 			glCanvas3D = {};
457 			glCanvas3D.__noSuchMethod__ = function(){return true;}
458 		}
459 		else
460 		{
461 			try
462 			{
463 				glCanvas3D = cvs.getContext('experimental-webgl');
464         glCanvas3D.viewport(0, 0, cvs.width, cvs.height);
465 			}
466 			catch(err){}
467         }
468 
469 		return glCanvas3D ? true : false;
470 	}
471 
472 	/**
473 		@private
474 		Enables depth testing, create necessary shaders, create the projection
475 		matrix and set the lighting uniform.
476 		
477 		Compiles and link the shaders.
478 
479 		@param {int} width of the canvas in pixels.
480 		@param {int} height of the canvas in pixels.
481 	*/
482 	this.init = function(width, height)
483 	{		
484 		if (glCanvas3D == null)
485 		{
486 			return false;
487 		}
488 		
489 		// set the context width and height. These are the base class
490 		// members.
491 		this.contextWidth = width;
492 		this.contextHeight = height;
493 		
494 		// enable the depth buffer, only needs to be done once, so do it here		
495 		glCanvas3D.enable(glCanvas3D.DEPTH_TEST);
496 		
497 		// we need to define this ourselves since it is not present in canvas 3d 0.4.3
498 		this.enable(c3dl.VERTEX_PROGRAM_POINT_SIZE);
499 
500 		// create the shader programs
501 		//this.geometryShader = this.createProgram(c3dl.material_vs+c3dl.light_vs+c3dl.model_vs, c3dl.model_fs).getProgramID();
502 		this.particleSystemShader = this.createProgram(c3dl.psys_vs, c3dl.psys_fs).getProgramID();
503 		this.pointShader = this.createProgram(c3dl.point_vs, c3dl.point_fs).getProgramID();
504 		this.lineShader = this.createProgram(c3dl.line_vs, c3dl.line_fs).getProgramID();
505 		this.pointSphereShader = this.createProgram(c3dl.point_sphere_vs, c3dl.point_sphere_fs).getProgramID();
506 		this.boundingSphereShader = this.createProgram(c3dl.bounding_sphere_vs, c3dl.bounding_sphere_fs).getProgramID();
507 
508 		// Template effects
509 
510 		// STANDARD
511 		c3dl.effects.STD_EFFECT = new c3dl.EffectTemplate();
512 		c3dl.effects.STD_EFFECT.addVertexShader(c3dl.material_vs+c3dl.light_vs+c3dl.model_vs);
513 		c3dl.effects.STD_EFFECT.addFragmentShader(c3dl.model_fs);
514 		c3dl.effects.STD_EFFECT.setRenderingCallback(c3dl.std_callback);
515 		c3dl.effects.STD_EFFECT.init();
516 
517 		c3dl.effects.STANDARD = new c3dl.Effect();
518 		c3dl.effects.STANDARD.init(c3dl.effects.STD_EFFECT);
519 		var prog = this.createProgram(c3dl.material_vs+c3dl.light_vs+c3dl.model_vs, c3dl.model_fs);
520 
521 		c3dl.effects.STANDARD.getEffectTemplate().addProgramObject(prog);
522 		this.programsWithLights.push(c3dl.effects.STANDARD.getEffectTemplate().getProgramID(this.ID));
523 		this.STANDARD_PROGRAM_ID = prog.getProgramID();
524     
525     // need to create the solid color effect explicitly
526     // since effects are really only created if an object uses them.
527     // and since we need it for gooch and cartoon....
528     ///
529 		c3dl.effects.SOLID_COLOR_EFFECT_TEMP = new c3dl.EffectTemplate();
530 		c3dl.effects.SOLID_COLOR_EFFECT_TEMP.addVertexShader(c3dl.solid_color_vs);
531 		c3dl.effects.SOLID_COLOR_EFFECT_TEMP.addFragmentShader(c3dl.solid_color_fs);
532 		c3dl.effects.SOLID_COLOR_EFFECT_TEMP.setRenderingCallback(c3dl.solid_color_callback);
533 		c3dl.effects.SOLID_COLOR_EFFECT_TEMP.init();
534 
535 		c3dl.effects.SOLID_COLOR_EFFECT = new c3dl.Effect();
536 		c3dl.effects.SOLID_COLOR_EFFECT.init(c3dl.effects.SOLID_COLOR_EFFECT_TEMP);
537 		var prog = this.createProgram(c3dl.solid_color_vs, c3dl.solid_color_fs);
538 
539 		c3dl.effects.SOLID_COLOR_EFFECT.getEffectTemplate().addProgramObject(prog);
540 		this.SOLID_COLOR_EFFECT_ID = prog.getProgramID();
541 
542     // GREYSCALE
543     c3dl.effects.GREYSCALE = new c3dl.EffectTemplate();
544     c3dl.effects.GREYSCALE.addVertexShader(c3dl.material_vs);
545     c3dl.effects.GREYSCALE.addVertexShader(c3dl.light_vs);
546     c3dl.effects.GREYSCALE.addVertexShader(c3dl.greyscale_vs);
547     c3dl.effects.GREYSCALE.addFragmentShader(c3dl.greyscale_fs);
548     c3dl.effects.GREYSCALE.setRenderingCallback(c3dl.greyscale_callback);
549     c3dl.effects.GREYSCALE.addParameter("color", Array, [0.3, 0.6, 0.1]);
550     c3dl.effects.GREYSCALE.init();
551 
552     // SOLID COLOR    
553     c3dl.effects.SOLID_COLOR = new c3dl.EffectTemplate();
554     c3dl.effects.SOLID_COLOR.addVertexShader(c3dl.solid_color_vs);
555     c3dl.effects.SOLID_COLOR.addFragmentShader(c3dl.solid_color_fs);
556     c3dl.effects.SOLID_COLOR.setRenderingCallback(c3dl.solid_color_callback);
557     c3dl.effects.SOLID_COLOR.addParameter("color", Array, [0.0, 0.0, 0.0]);
558     c3dl.effects.SOLID_COLOR.init();
559 
560     // SEPIA
561     c3dl.effects.SEPIA = new c3dl.EffectTemplate();
562     c3dl.effects.SEPIA.addVertexShader(c3dl.material_vs);
563     c3dl.effects.SEPIA.addVertexShader(c3dl.light_vs);
564     c3dl.effects.SEPIA.addVertexShader(c3dl.sepia_vs);
565     c3dl.effects.SEPIA.addFragmentShader(c3dl.sepia_fs);
566     c3dl.effects.SEPIA.setRenderingCallback(c3dl.sepia_callback);
567     c3dl.effects.SEPIA.addParameter("color", Array, [1.2, 1.0, 0.8]);
568     c3dl.effects.SEPIA.init();
569 
570     // CARTOON
571     c3dl.effects.CARTOON = new c3dl.EffectTemplate();
572     c3dl.effects.CARTOON.addVertexShader(c3dl.cartoon_vs);
573     c3dl.effects.CARTOON.addFragmentShader(c3dl.light_vs);
574     c3dl.effects.CARTOON.addFragmentShader(c3dl.cartoon_fs);
575     c3dl.effects.CARTOON.setRenderingCallback(c3dl.cartoon_callback);
576     c3dl.effects.CARTOON.addParameter("qMap", String);
577     c3dl.effects.CARTOON.addParameter("outline", Boolean, true);
578     c3dl.effects.CARTOON.init();
579 
580 		// GOOCH
581 		c3dl.effects.GOOCH = new c3dl.EffectTemplate();
582 		c3dl.effects.GOOCH.addVertexShader(c3dl.gooch_vs);
583 		c3dl.effects.GOOCH.addFragmentShader(c3dl.light_vs);
584 		c3dl.effects.GOOCH.addFragmentShader(c3dl.gooch_fs);
585 		c3dl.effects.GOOCH.setRenderingCallback(c3dl.gooch_callback);
586 		c3dl.effects.GOOCH.addParameter("coolColor", Array, [0,0,1] );
587 		c3dl.effects.GOOCH.addParameter("warmColor", Array, [0.5,0.5,0.0]);
588 		c3dl.effects.GOOCH.addParameter("surfaceColor", Array, [0.1,0.1,0.1]);
589     c3dl.effects.GOOCH.addParameter("outline", Boolean, true);
590 		c3dl.effects.GOOCH.init();
591 
592 		this.texManager = new c3dl.TextureManager(glCanvas3D);
593 
594 		// iterate over all the textures the user added before the renderer
595 		// was initialized and add them now.
596 		for(var i in this.textureQueue)
597 		{
598 			if(this.textureQueue[i])
599 			{
600 				this.texManager.addTexture(this.textureQueue[i]);
601 			}
602 		}
603 
604 		return true;
605 	}
606 	
607 	/**
608 		@private
609 		Render the bounding sphere
610 		
611 		@param {c3dl.BoundingSphere} boundingSphere
612 	*/
613 	this.renderBoundingSphere = function(boundingSphere)
614 	{
615     // create an short alias
616     var shader = this.boundingSphereShader;
617     glCanvas3D.useProgram(shader);
618 
619     if( this.pointSphereRenderReady == false )
620     {
621       // create VBO and set the data
622       this.pointSphereRenderSetup();
623     }
624     else
625     {
626       c3dl.pushMatrix();
627       
628       var top = c3dl.peekMatrix();
629       var mat = c3dl.makeIdentityMatrix();
630         
631       // set the bounding sphere's position
632       mat[12] = top[12] + boundingSphere.getPosition()[0];
633       mat[13] = top[13] + boundingSphere.getPosition()[1];
634       mat[14] = top[14] + boundingSphere.getPosition()[2];
635       mat[0] = mat[5] = mat[10] = boundingSphere.getRadius();
636 
637       c3dl.matrixMode(c3dl.PROJECTION);
638       var proj = c3dl.peekMatrix();
639       c3dl.matrixMode(c3dl.MODELVIEW);
640   
641       // create a modelviewprojection matrix.  By doing this, we can multiply
642       // 3 matrices together once per model instead of once per vertex.
643       var MVPMatrix = c3dl.multiplyMatrixByMatrix(proj, mat );
644       this.setUniformMatrix(shader, "modelViewProjMatrix", MVPMatrix);
645 
646       this.setVertexAttribArray(shader, "Vertex", 3, this.pointSphereVBOVert);
647       glCanvas3D.drawArrays(glCanvas3D.POINTS,0, c3dl.BOUNDING_SPHERE_VERTICES.length/3);
648       c3dl.popMatrix();
649     }
650   }
651 	
652 	/**
653 		@private
654 		Render a geometry
655 		
656 		@param {c3dl.Geometry} obj
657 	*/
658 	this.renderGeometry = function(obj)
659 	{	
660 		// get the object's effect
661 		if(obj.getEffect())
662 		{
663 			//
664 			var effect = obj.getEffect().getEffectTemplate();
665 			
666 			var progObjID = effect.getProgramID(this.ID);
667 					
668 			// If the effect's shaders have not yet been compiled for this renderer,
669 			// compile them.
670 			if( progObjID == -1)
671 			{
672 				var vertexShaders = effect.getVertexShaders();
673 				var fragmentShaders = effect.getFragmentShaders();
674 
675 				// join all the shaders, but don't insert a delimiter, that
676 				// would create a syntax error for the shaders.
677 				var joinedVertexShaders = vertexShaders.join('');
678 				var joinedFragmentShaders = fragmentShaders.join('');
679 
680 				var programObject = this.createProgram(joinedVertexShaders, joinedFragmentShaders);
681 
682 				// if the effect was successfully compiled, render it using the effect
683 				if(programObject)
684 				{					
685 					effect.addProgramObject(programObject);
686 					
687 					// check if the user added the light vertex shader source.
688 					// if they did, we'll need to update the light states every
689 					// update for that shader.
690 					for(var i = 0; i < vertexShaders.length; i++)
691 					{
692 						if(vertexShaders[i] == c3dl.light_vs)
693 						{
694 							this.programsWithLights.push(programObject.getProgramID());
695 							glCanvas3D.useProgram(programObject.getProgramID());
696 							this.setUniformi(programObject.getProgramID(), "lightingOn", true);
697 						}
698 					}
699 
700 					for(var i = 0; i < fragmentShaders.length; i++)
701 					{
702 						if(fragmentShaders[i] == c3dl.light_vs)
703 						{
704 							this.programsWithLights.push(programObject.getProgramID());
705 							glCanvas3D.useProgram(programObject.getProgramID());
706 							this.setUniformi(programObject.getProgramID(), "lightingOn", true);
707 						}
708 					}
709 				}
710 				else
711 				{
712 					c3dl.debug.logWarning("could not compile effect shader(s).");
713 					c3dl.debug.logInfo(joinedVertexShaders);
714 					c3dl.debug.logInfo(joinedFragmentShaders);
715 				}
716 			}
717 			// if the effect has already been compiled, go ahead and render the geometry.
718 			else
719 			{
720 				var renderingObj = {};
721 				
722 				// user will need to query states of the context.
723 				renderingObj["context"] = glCanvas3D;
724 				renderingObj["getContext"] = function (){ return this.context;};
725 				
726 				// user will need to query states of the renderer.
727 				// enventually the renderer will completely abtract the context and
728 				// the context will not need to be passed in. But that requires all
729 				// functions to be wrapped.
730 				renderingObj["renderer"] = this;
731 				renderingObj["getRenderer"] = function (){ return this.renderer;};
732 
733 				// user will need to set the current program.
734 				renderingObj['programObjectID'] = progObjID;
735 				renderingObj['getProgramObjectID'] = function(){ return this.programObjectID;};
736 				
737 				// user will need the actual geometry to render.
738 				renderingObj['geometry'] = obj;
739 				renderingObj['getGeometry'] = function(){ return this.geometry;};
740 								
741 				var cb = effect.getRenderingCallback();
742 				cb(renderingObj);
743 			}
744 
745 		}
746 		
747 		// if the geometry didn't have an effect, we'll render it using
748 		// the standard shader.
749 		else
750 		{
751 			var renderingObj = {};
752 			
753 			//
754 			renderingObj["context"] = glCanvas3D;
755 			renderingObj["getContext"] = function (){ return this.context;};
756 			
757 			//
758 			renderingObj["renderer"] = this;
759 			renderingObj["getRenderer"] = function (){ return this.renderer;};
760 			
761 			//
762 			renderingObj['programObjectID'] = this.STANDARD_PROGRAM_ID;
763 			renderingObj['getProgramObjectID'] = function(){ return this.programObjectID;};
764 			
765 			//
766 			renderingObj['geometry'] = obj;
767 			renderingObj['getGeometry'] = function(){ return this.geometry;};
768 
769 			c3dl.std_callback(renderingObj);
770 		}
771 	}
772 
773 	
774 	/**
775 		@private	
776 		Render a particle system.
777 		
778 		@param {c3dl.ParticleSystem} psys
779 	*/
780 	this.renderParticleSystem = function(psys)
781 	{
782 		// create shorter alias
783 		var shader = this.particleSystemShader;
784 		glCanvas3D.useProgram(shader);
785 
786 		var usingTexture = false;
787 		var texturePath = psys.getTexture();
788 		var texID = this.texManager.getID(texturePath);
789 		var texAttribLoc = glCanvas3D.getAttribLocation(shader, "Texture");
790       
791 		// if the texture isn't loaded, but this collation element has one, 
792 		// queue one up
793 		if(texID == -1 && texturePath)
794 		{
795 			this.texManager.addTexture(texturePath);
796 		}
797 		
798 		if(texID != -1 && texturePath && psys.getTexCoords())
799 		{
800 			glCanvas3D.activeTexture(glCanvas3D.TEXTURE0);
801 			glCanvas3D.bindTexture(glCanvas3D.TEXTURE_2D,texID);
802 			this.setVertexAttribArray(shader, "Texture", 2, psys.getVBOTexCoords());
803 			usingTexture = true;
804 
805       glCanvas3D.texParameteri( glCanvas3D.TEXTURE_2D, glCanvas3D.TEXTURE_WRAP_S, glCanvas3D.CLAMP_TO_EDGE);
806       glCanvas3D.texParameteri( glCanvas3D.TEXTURE_2D, glCanvas3D.TEXTURE_WRAP_T, glCanvas3D.CLAMP_TO_EDGE);
807 		}
808 		else
809     {
810 			glCanvas3D.activeTexture(glCanvas3D.TEXTURE0);
811 			glCanvas3D.disableVertexAttribArray(texAttribLoc);
812 			//glCanvas3D.bindTexture(glCanvas3D.TEXTURE_2D,-1);
813 		}
814     this.setUniformi(shader, "usingTexture", usingTexture);
815     this.setUniformMatrix(shader, "rot", [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]);
816 		this.setVertexAttribArray(shader, "Vertex", 3, psys.getVBOVertices());
817 
818 		for(var i = 0; i < psys.getNumParticles(); i++)
819 		{
820 			if(psys.getParticle(i).isAlive())
821 			{
822                 var pSize = psys.getParticle(i).getSize();
823         
824                 this.setUniformf(shader, "Color", psys.getParticle(i).getColor());
825 
826 				c3dl.matrixMode(c3dl.PROJECTION);
827 				var projectionMatrix = c3dl.peekMatrix();
828 				c3dl.matrixMode(c3dl.MODELVIEW);
829 				var viewMatrix = c3dl.peekMatrix();
830 
831         //
832 				var modelMatrix = psys.getParticle(i).getTransform();
833         modelMatrix = c3dl.multiplyMatrixByMatrix(modelMatrix, [pSize,0,0,0,  0,pSize,0,0,  0,0,pSize,0,  0,0,0,1]);
834 
835 				// create a ModelViewProjection matrix.  By doing this, we can multiply
836 				// 3 matrices together once per particle instead of once per vertex
837 				var modelViewProjMatrix = c3dl.multiplyMatrixByMatrix(viewMatrix,modelMatrix);
838 				modelViewProjMatrix = c3dl.multiplyMatrixByMatrix(projectionMatrix, modelViewProjMatrix );
839 				this.setUniformMatrix(shader, "modelViewProjMatrix", modelViewProjMatrix);
840         
841         glCanvas3D.drawArrays(glCanvas3D.TRIANGLE_FAN, i , 4);
842 			}
843 		}
844 	}
845 	
846 	/**
847 		@private
848 		Render a set of lines.
849 
850 		@param {Array} lines
851 	*/
852 	this.renderLines = function(lines)
853 	{
854 		if(lines.length > 0)
855 		{
856 			// create a short alias for this.lineShader
857 			var shader = this.lineShader;
858 			glCanvas3D.useProgram(shader);
859 
860 			// camera placed the view matrix at the bottom of the stack
861 			var modelViewMatrix = c3dl.peekMatrix();
862 			c3dl.matrixMode(c3dl.PROJECTION);
863 			var projectionMatrix = c3dl.peekMatrix();
864 			c3dl.matrixMode(c3dl.MODELVIEW);
865 
866 			// create a ModelViewProjection matrix.  By doing this, we can multiply
867 			// 3 matrices together once per model instead of once per vertex
868 			var modelViewProjMatrix = c3dl.multiplyMatrixByMatrix(projectionMatrix, modelViewMatrix );
869 			this.setUniformMatrix(shader, "modelViewProjMatrix", modelViewProjMatrix);
870 
871 
872 			// we need to render each line individually since each can have 
873 			// a different width.
874 				glCanvas3D.lineWidth(4);
875 
876 				var coords = [];
877 				var cols = [];
878 				for(var i=0; i < lines.length; i++)
879 				{
880 					coords.push(lines[i].getCoordinates()[0]);
881 					coords.push(lines[i].getCoordinates()[1]);
882 					coords.push(lines[i].getCoordinates()[2]);
883 					coords.push(lines[i].getCoordinates()[3]);
884 					coords.push(lines[i].getCoordinates()[4]);
885 					coords.push(lines[i].getCoordinates()[5]);
886 					
887 					cols.push(lines[i].getColors()[0]);
888 					cols.push(lines[i].getColors()[1]);
889 					cols.push(lines[i].getColors()[2]);
890 					cols.push(lines[i].getColors()[3]);
891 					cols.push(lines[i].getColors()[4]);
892 					cols.push(lines[i].getColors()[5]);
893 				}
894 
895 				if(this.lineVertBuffer == null)
896 				{
897 					this.lineVertBuffer = {};
898 					this.lineVertBuffer.position = glCanvas3D.createBuffer();
899 				}
900 
901 				glCanvas3D.bindBuffer(glCanvas3D.ARRAY_BUFFER, this.lineVertBuffer.position);
902 				glCanvas3D.bufferData(glCanvas3D.ARRAY_BUFFER, new WebGLFloatArray(coords), glCanvas3D.STREAM_DRAW);
903 				this.setVertexAttribArray(shader, "Vertex", 3, this.lineVertBuffer.position );
904 
905 				if(this.lineColBuffer == null)
906 				{
907 					this.lineColBuffer = {};
908 					this.lineColBuffer.position = glCanvas3D.createBuffer();
909 				}
910 
911 				glCanvas3D.bindBuffer(glCanvas3D.ARRAY_BUFFER, this.lineColBuffer.position);
912 				glCanvas3D.bufferData(glCanvas3D.ARRAY_BUFFER, new WebGLFloatArray(cols), glCanvas3D.STREAM_DRAW);
913 				this.setVertexAttribArray(shader, "Color", 3, this.lineColBuffer.position );
914 
915 				glCanvas3D.drawArrays(glCanvas3D.LINES, 0, coords.length/3);
916 		}
917 	}
918 
919 	/**
920 		@private
921 		@param {Array} pointPositions
922 		@param {Array} pointColors
923 		@param {Array} attenuation
924 		@param {bool} pointSmooth
925     @param {int} mode
926     @param {float} size
927 	*/
928 	this.renderPoints = function(pointPositions, pointColors, attenuation, pointSmooth, mode, size)
929 	{
930 		// trying to render an empty list will result in an opengl error
931 		if(pointPositions.length > 0 && pointColors.length > 0)
932 		{
933 			if( mode == c3dl.POINT_MODE_POINT)
934 			{
935 				// create a shorter reference name.
936 				var shader = this.pointShader;
937 				glCanvas3D.useProgram(shader);
938 
939 				// camera placed the view matrix at the bottom of the stack
940 				var viewMatrix = c3dl.peekMatrix();
941 				c3dl.matrixMode(c3dl.PROJECTION);
942 				var projectionMatrix = c3dl.peekMatrix();
943 				c3dl.matrixMode(c3dl.MODELVIEW);
944 
945 				// if point smoothing is on, points will be rendered as circles, 
946 				// otherwise they will be rendered as squares.
947 				pointSmooth ? this.enable(c3dl.POINT_SMOOTH) : this.disable(c3dl.POINT_SMOOTH);
948 
949 				// create a ModelViewProjection matrix.  By doing this, we can multiply
950 				// 3 matrices together once instead of once per point
951 				var modelViewProjMatrix = c3dl.multiplyMatrixByMatrix(projectionMatrix, viewMatrix );
952 				this.setUniformMatrix(shader, "viewMatrix", viewMatrix);
953 				this.setUniformMatrix(shader, "modelViewProjMatrix", modelViewProjMatrix);
954 				this.setUniformf(shader, "attenuation", attenuation);
955 
956 				if(this.pointVertBuffer == null)
957 				{	
958 					this.pointVertBuffer = {};
959 					this.pointVertBuffer.position = glCanvas3D.createBuffer();
960 				}
961 
962 				glCanvas3D.bindBuffer(glCanvas3D.ARRAY_BUFFER, this.pointVertBuffer.position);
963 				glCanvas3D.bufferData(glCanvas3D.ARRAY_BUFFER, new WebGLFloatArray(pointPositions), glCanvas3D.STREAM_DRAW);
964 				this.setVertexAttribArray(shader, "Vertex", 3, this.pointVertBuffer.position);
965 				
966 				if(this.pointColBuffer == null)
967 				{
968 					this.pointColBuffer = {};
969 					this.pointColBuffer.position = glCanvas3D.createBuffer();
970 				}
971 
972 				glCanvas3D.bindBuffer(glCanvas3D.ARRAY_BUFFER, this.pointColBuffer.position);
973 				glCanvas3D.bufferData(glCanvas3D.ARRAY_BUFFER, new WebGLFloatArray(pointColors), glCanvas3D.STREAM_DRAW);
974 				this.setVertexAttribArray(shader, "Color", 3, this.pointColBuffer.position);
975 				glCanvas3D.drawArrays(glCanvas3D.POINTS, 0, pointPositions.length/3);
976 			}
977 			else if(mode == c3dl.POINT_MODE_SPHERE)
978 			{
979         // create an short alias
980 				var shader = this.pointSphereShader;
981 				glCanvas3D.useProgram(shader);
982 
983         if( this.pointSphereRenderReady == false )
984         {
985           // create vbo and set the data
986           this.pointSphereRenderSetup();
987         }
988         else
989         {
990           c3dl.pushMatrix();
991         
992           for( var i=0 ; i < pointPositions.length; i+=3)
993           {
994             // 
995             var mat = c3dl.makeIdentityMatrix();	
996             mat[12] = pointPositions[i];
997             mat[13] = pointPositions[i+1];
998             mat[14] = pointPositions[i+2];
999             mat[0] = mat[5] = mat[10] = size;
1000 
1001             mat = c3dl.multiplyMatrixByMatrix(c3dl.peekMatrix(), mat);
1002 
1003             c3dl.matrixMode(c3dl.PROJECTION);
1004             var proj = c3dl.peekMatrix();
1005             c3dl.matrixMode(c3dl.MODELVIEW);
1006         
1007             // create a modelviewprojection matrix.  By doing this, we can multiply
1008             // 3 matrices together once per model instead of once per vertex.
1009             var MVPMatrix = c3dl.multiplyMatrixByMatrix(proj, mat );
1010             this.setUniformMatrix(shader, "modelViewProjMatrix", MVPMatrix);
1011             this.setUniformf(shader, "Color", [pointColors[i],pointColors[i+1],pointColors[i+2]]);
1012 
1013             this.setVertexAttribArray(shader, "Vertex", 3, this.pointSphereVBOVert);
1014             glCanvas3D.drawArrays(glCanvas3D.TRIANGLES,0, c3dl.BOUNDING_SPHERE_VERTICES.length/3);
1015             c3dl.popMatrix();
1016           }
1017         }
1018 			}
1019 		}
1020 	}
1021 
1022 	/**
1023 		@private
1024 
1025 		@param {int} shader
1026 		@param {String} varName
1027 		@param {int} size
1028 		@param {Array} array
1029 	*/
1030 	/*this.setVertexAttribArray = function(shader, varName, size, array, vbo)
1031 	{
1032 		var attribLoc = glCanvas3D.getAttribLocation(shader, varName);
1033 
1034 		if(attribLoc != c3dl.SHADER_VAR_NOT_FOUND)
1035 		{
1036 			glCanvas3D.bindBuffer(glCanvas3D.ARRAY_BUFFER, vbo);
1037 			glCanvas3D.vertexAttribPointer(attribLoc, size, glCanvas3D.FLOAT, false, 0, 0);
1038 			glCanvas3D.enableVertexAttribArray(attribLoc);
1039 		}
1040 		else
1041 		{
1042 			c3dl.debug.logError("Attribute variable '" +  varName + "' not found in shader with ID = " + shader);
1043 		}
1044 	}*/
1045 	
1046 	
1047 	
1048 	this.setVertexAttribArray = function(shader, varName, size, vbo)
1049 	{
1050 		var attribLoc = glCanvas3D.getAttribLocation(shader, varName);
1051 
1052 		if(attribLoc != c3dl.SHADER_VAR_NOT_FOUND)
1053 		{
1054 			glCanvas3D.bindBuffer(glCanvas3D.ARRAY_BUFFER, vbo);
1055 			glCanvas3D.vertexAttribPointer(attribLoc, size, glCanvas3D.FLOAT, false, 0, 0);
1056 			glCanvas3D.enableVertexAttribArray(attribLoc);
1057 		}
1058 		else
1059 		{
1060 			c3dl.debug.logError("Attribute variable '" +  varName + "' not found in shader with ID = " + shader);
1061 		}
1062 	}
1063 	
1064 	/**
1065 		Sets the uniform matrix variable 'varName' to the value specified by 'value'.
1066 		Before calling this function, you must ensure the program object with
1067 		the variable name 'varName' has been installed as part of the current
1068 		rendering state by calling useProgram().<br />
1069 		<br />
1070 		The size of the matrix must be 16 elements.<br />
1071 		<br />
1072 		On some systems, if the variable exists in the shader but isn't used,
1073 		the compiler will remove it. An error message will be displayed if the
1074 		non-existant variable is set.<br />
1075 		<br />
1076 		If the variable could not be found for any other reason, an error is 
1077 		displayed.
1078 		
1079 		@param {int} programObjectID The shader where the variable resides.
1080 		@param {String} varName The name of the matrix variable.
1081 		@param {Array} matrix 16 element matrix.
1082 	*/
1083 	this.setUniformMatrix = function(programObjectID, varName, matrix)
1084 	{
1085 		var varLocation = glCanvas3D.getUniformLocation(programObjectID, varName);
1086 
1087 		// the variable won't be found if it was optimized out.
1088 		if( varLocation != c3dl.SHADER_VAR_NOT_FOUND)
1089 		{
1090 			glCanvas3D.uniformMatrix4fv(varLocation, false, matrix);
1091 		}
1092 		else
1093 		{
1094 			c3dl.debug.logError("Uniform matrix variable '" + varName + "' not found in program object.");
1095 		}
1096 	}
1097 
1098 	/**
1099 		Sets the uniform variable 'varName' to the value specified by 'value'.
1100 		Before calling this function, you must ensure the program object with
1101 		the variable name 'varName' has been installed as part of the current
1102 		rendering state by calling useProgram().<br />
1103 		<br />
1104 		The size of the value will be queried and depending on its size, the 
1105 		appropriate OpenGL command will be called either uniform1f or 
1106 		uniform{1|2|3|4}fv.<br />
1107 		<br />
1108 		On some systems, if the variable exists in the shader but isn't used,
1109 		the compiler will remove it. An error message will be displayed if the
1110 		non-existant variable is set.<br />
1111 		<br />
1112 		If the variable could not be found for any other reason, an error is 
1113 		displayed.
1114 		
1115 		@param {int} programObjectID The shader where the variable resides.
1116 		@param {String} varName The name of the variable.
1117 		@param {float|Array} value The value to assign the variable.
1118 	*/
1119 	this.setUniformf = function (shader, varName, value)
1120 	{
1121 		var varLocation = glCanvas3D.getUniformLocation(shader, varName);
1122         // the variable won't be found if it was optimized out.
1123 		if( varLocation != c3dl.SHADER_VAR_NOT_FOUND)
1124 		{
1125 			if		(value.length == 4){glCanvas3D.uniform4fv( varLocation, value);}
1126 			else if	(value.length == 3){glCanvas3D.uniform3fv( varLocation, value);}
1127 			else if	(value.length == 2){glCanvas3D.uniform2fv( varLocation, value);}
1128 			else {glCanvas3D.uniform1f( varLocation, value);}
1129 		}
1130 		else
1131 		{
1132 			c3dl.debug.logError('Uniform variable "' + varName + '" not found in program object.');
1133 		}
1134 	}
1135 
1136 	/**
1137 		Sets the uniform variable 'varName' to the value specified by 'value'.
1138 		Before calling this function, you must ensure the program object with
1139 		the variable name 'varName' has been installed as part of the current
1140 		rendering state by calling useProgram().<br />
1141 		<br />
1142 		The size of the value will be queried and depending on its size, the 
1143 		appropriate OpenGL command will be called either uniform1i or 
1144 		uniform{1|2|3|4}iv.<br />
1145 		<br />
1146 		On some systems, if the variable exists in the shader but isn't used,
1147 		the compiler will remove it. An error message will be displayed if the
1148 		non-existant variable is set.<br />
1149 		<br />
1150 		If the variable could not be found for any other reason, an error is 
1151 		displayed.
1152 		
1153 		@param {int} programObjectID The shader where the variable resides.
1154 		@param {String} varName The name of the variable.
1155 		@param {int|Array} value The value to assign the variable.
1156 	*/
1157 	this.setUniformi = function (programObjectID, varName, value)
1158 	{
1159 		var varLocation = glCanvas3D.getUniformLocation(programObjectID, varName);
1160 
1161 		// the variable won't be found if it was optimized out.
1162 		if( varLocation != c3dl.SHADER_VAR_NOT_FOUND)
1163 		{
1164 			if		(value.length == 4){glCanvas3D.uniform4iv(varLocation, value);}
1165 			else if	(value.length == 3){glCanvas3D.uniform3iv(varLocation, value);}
1166 			else if	(value.length == 2){glCanvas3D.uniform2iv(varLocation, value);}
1167 			else {glCanvas3D.uniform1i(varLocation, value);}
1168 		}
1169 		else
1170 		{
1171 			c3dl.debug.logError('Uniform variable "' + varName + '" not found in program object.');
1172 		}
1173 	}
1174 	
1175 	/**
1176 		@private
1177 		Enable an OpenGL server-side capability.
1178 
1179 		@param {int} capability
1180 	*/
1181 	this.enable = function(capability)
1182 	{
1183 		try{
1184 			// check if its defined
1185 			if(capability)
1186 			{
1187 				glCanvas3D.enable(capability);
1188 			}
1189 			else
1190 			{
1191 				c3dl.debug.logWarning("Enable command passed undefined value.");
1192 			}
1193 		}
1194 		catch(e)
1195 		{
1196 			c3dl.debug.logException("Exception name:" + e.name + "<br />" +
1197 									"Exception msg: " + e.message + "<br />" + 
1198 									"Capability: " + capability);
1199 		}
1200 	}
1201 	
1202 	/**
1203 		@private
1204 
1205 		Disable a server-side OpenGL capability. This wraps the OpenGL ES
1206 		'disable' command and adds a conditional to make sure the capability is
1207 		supported before trying to change the state.  If the capability is not
1208 		supported and the state is change, the script could be prevented 
1209 		from running.
1210 		
1211 		@param {int} capability OpenGL ES capability
1212 	*/
1213 	this.disable = function(capability)
1214 	{
1215 		if(capability)
1216 		{
1217 			glCanvas3D.disable(capability);
1218 		}
1219 		else
1220 		{
1221 			c3dl.debug.logWarning("disable command passed undefined value.");
1222 		}
1223 	}
1224 }
1225 
1226 c3dl.WebGL.prototype = new c3dl.Renderer;
1227