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 c3dl.Geometry is a container for the primitiveSets of a 
  8 	geometric object.
  9 */
 10 c3dl.Geometry = function()
 11 {
 12 	// a geometry is composed of different collation elements (sets of primitives)
 13 	// collation elements are <triangles>, <polylist>, <polygon>, etc.
 14 	this.primitiveSets = [];
 15 	this.effect = null;
 16 	
 17 	// the first time geometries are rendered, their VBO's need to
 18 	// be setup. Can't do this when Collada objects are created
 19 	// because we don't yet have a graphics context.
 20 	this.firstTimeRender = true;
 21 
 22 	/**
 23 		@private
 24 		
 25 		Used by the collada loader
 26 	*/
 27 	this.addPrimitiveSet = function(primitiveSet)
 28 	{
 29 		this.primitiveSets.push(primitiveSet);
 30 	}
 31 
 32 	/**
 33 		@private
 34 
 35 		Used by the ColladaManager
 36 	*/
 37 	this.clone = function(other)
 38 	{
 39 		// 
 40 		for(var i = 0; i < other.primitiveSets.length; i++)
 41 		{
 42 			this.primitiveSets.push( other.primitiveSets[i].getCopy());
 43 		}
 44 	}
 45 
 46 
 47 	/**
 48 		@private
 49 
 50 		Used by the ColladaManager
 51 	*/
 52 	this.getCopy = function()
 53 	{
 54 		var geometry = new c3dl.Geometry();
 55 		geometry.clone(this);
 56 		return geometry;
 57 	}
 58 
 59 
 60 	/**
 61 		@private
 62 		Get the effect of this geometry.
 63 
 64 		@param {c3dl.Effect} The effect of this geometry.
 65 	*/
 66 	this.getEffect = function()
 67 	{
 68 		return this.effect;
 69 	}
 70 
 71 	/**
 72 		Get the array of primitive sets for this geometry.
 73 		
 74 		@returns {Array} The primitive sets for this geometry.
 75 	*/
 76 	this.getPrimitiveSets = function()
 77 	{
 78 		return this.primitiveSets;
 79 	}
 80 
 81 
 82 	/**
 83 		@private
 84 		
 85 		Does the given ray intersect with any of the geometry's primitive set's
 86 		bounding spheres?
 87 		
 88 		@param {Array} rayOrigin
 89 		@param {Array} rayDir
 90 	*/
 91 	this.rayIntersectsEnclosures = function(rayOrigin, rayDir)
 92 	{
 93 		var mat = c3dl.peekMatrix();
 94 		
 95 		for(var i = 0; i < this.primitiveSets.length; i++)
 96 		{
 97 			var bs = this.primitiveSets[i].getBoundingSphere();
 98 			var longestVec;
 99 
100 			var leftLen = c3dl.vectorLength([mat[0], mat[1], mat[2]]);
101 			var upLen   = c3dl.vectorLength([mat[4], mat[5], mat[6]]);
102 			var dirLen  = c3dl.vectorLength([mat[8], mat[9], mat[10]]); 
103 
104 			longestVec = leftLen > upLen ? leftLen : upLen;
105 			longestVec = longestVec > dirLen? longestVec : dirLen;
106 
107 			bs.setPosition([mat[12], mat[13], mat[14]])
108 			bs.scale([longestVec,longestVec,longestVec]);
109 
110 			if(c3dl.rayIntersectsSphere(rayOrigin, rayDir, bs.getPosition(), bs.getRadius()))
111 			{				
112 				return true;
113 			}
114 		}
115 		return false;
116 	}
117 
118 
119 	/**
120 		@private
121 
122 		Does the mesh in this geometry node intersect with the ray?
123 			
124 		@param {Array} rayOrigin
125 		@param {Array} rayDir
126 	*/
127 	this.rayIntersectsTriangles = function(rayOrigin, rayDir)
128 	{		
129 		var mat = c3dl.inverseMatrix(c3dl.peekMatrix());
130 		var rayorigin = c3dl.multiplyMatrixByVector(mat, rayOrigin);
131 		var raydir = c3dl.normalizeVector(c3dl.multiplyMatrixByDirection(mat, rayDir));
132 
133 		// allocate and resuse these vertices to prevent allocation and deletion every face.
134 		var vert1 = new Array(3);
135 		var vert2 = new Array(3);
136 		var vert3 = new Array(3);
137 		
138 		for(var i = 0; i < this.primitiveSets.length; i++)
139 		{
140 			var vertices = this.primitiveSets[i].getVertices();
141 
142 			// Iterate over each face of the object and test it against the ray.
143 			for (var j = 0; j < vertices.length; j += 9)
144 			{
145 				// 3 points of a triangle with the object's position offset
146 				vert1[0] = vertices[j];
147 				vert1[1] = vertices[j+1]
148 				vert1[2] = vertices[j+2];
149 
150 				vert2[0] = vertices[j+3];
151 				vert2[1] = vertices[j+4];
152 				vert2[2] = vertices[j+5];
153 
154 				vert3[0] = vertices[j+6];
155 				vert3[1] = vertices[j+7];
156 				vert3[2] = vertices[j+8];
157 
158 				if (c3dl.rayIntersectsTriangle(rayorigin, raydir, vert1, vert2, vert3))
159 				{
160 					return true;
161 				}
162 			}
163 		}
164 		return false;
165 	}
166 
167 	
168 	
169 	/**
170 		@private
171 
172 		Called automatically
173 	*/
174 	this.render = function(glCanvas3D, scene)
175 	{		
176 		if (glCanvas3D == null)
177 		{
178 			c3dl.debug.logWarning('Geometry::render() called with a null glCanvas3D');	
179 			return false;
180 		}
181 		
182 		// The first time this is rendered, setup VBOs.
183 		if(this.firstTimeRender == true)
184 		{
185 			// iterate over the primitive sets and setup their VBOs
186 			for(var i = 0; i < this.primitiveSets.length; i++)
187 			{
188 				this.primitiveSets[i].setupVBO(glCanvas3D);
189 			}
190 			this.firstTimeRender = false;
191 		}
192 
193 		scene.getRenderer().renderGeometry(this);
194 
195 		if( scene.getBoundingVolumeVisibility() )
196 		{
197 			// tell all the collation elements/ primitive sets to render their bounding spheres.
198 			for(var i = 0; i < this.primitiveSets.length; i++)
199 			{		
200 				var bs = this.primitiveSets[i].getBoundingSphere();
201 				if(bs)
202 				{
203 					bs.render(scene);
204 				}
205 			}
206 		}
207 	}
208 
209 
210 	/**
211 		@private
212 		
213 		Set the effect of this geometry. The geometry has primitive sets, 
214 		but those cannot be set directly. All primitive sets under this 
215 		geometric object will be rendered the same.
216 		
217 		@param {c3dl.Effect} effect
218 	*/
219 	this.setEffect = function(effect)
220 	{
221 		this.effect = effect;
222 	}
223 
224 
225 	/**
226 		@private
227 		
228 		@param {c3dl.Material} material
229 	*/
230 	this.setMaterial = function(material)
231 	{
232 		for(var i=0; i < this.primitiveSets.length; i++)
233 		{
234 			this.primitiveSets[i].setMaterial(material);
235 		}
236 	}
237 
238 
239 	/**
240 		@private
241 		
242 		@param {} texture
243 	*/
244 	this.setTexture = function(texture)
245 	{
246 		for(var i=0; i < this.primitiveSets.length; i++)
247 		{
248 			this.primitiveSets[i].setTexture(texture);
249 		}
250 	}
251 
252 
253 	/**
254 		@private
255 
256 		Called automatically
257 	*/
258 	this.update = function(timeStep)
259 	{
260 		//
261 		for(var i = 0; i < this.primitiveSets.length; i++)
262 		{
263 			var bs = this.primitiveSets[i].getBoundingSphere();
264 			if(bs)
265 			{
266 				//bs.setPosition(this.pos);
267 				bs.setPosition([0,0,0]);
268 			}
269 		}
270 	}
271 }
272