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 
  8 /**
  9 	@class c3dl.FreeCamera A camera which can be freely moved around in a scene.
 10 	@augments c3dl.Camera
 11 */
 12 c3dl.FreeCamera = c3dl.inherit(c3dl.Camera, function()
 13 {
 14 	c3dl._superc(this);
 15 
 16 	// Delta Values for Animations
 17 	this.linVel	= [0.0, 0.0, 0.0]; // Animation of positions
 18 	this.angVel	= [0.0, 0.0, 0.0]; // Animations of rotation around (side Vector, up Vector, dir Vector)
 19 });
 20 
 21 /**
 22 	Get the camera's angular velocity
 23 	
 24 	@return {Array}
 25 */
 26 c3dl.FreeCamera.prototype.getAngularVel	= function()
 27 {
 28 	return [this.angVel[0], this.angVel[1], this.angVel[2]];
 29 }
 30 
 31 
 32 /**
 33 	Get the camera's linear velocity
 34 	
 35 	@returns {Array}
 36 */
 37 c3dl.FreeCamera.prototype.getLinearVel = function()
 38 {
 39 	return [this.linVel[0], this.linVel[1], this.linVel[2]];
 40 }
 41 
 42 
 43 /**
 44 	Rotate around the Side Vector by a hard amount (No Animation).
 45 
 46 	@param {float} angle in radians.
 47 */
 48 c3dl.FreeCamera.prototype.pitch = function(angle)
 49 {
 50 	this.rotateOnAxis(this.left, angle);	
 51 }
 52 
 53 
 54 /**
 55 	Rotate around the Dir Vector by a hard amount (No Animation).
 56 
 57 	@param {float} angle in radians.
 58 */
 59 c3dl.FreeCamera.prototype.roll = function(angle)
 60 {
 61 	this.rotateOnAxis(this.dir, angle);
 62 }
 63 
 64 
 65 /**
 66 	Rotate camera on an Axis which is centered on the position of the camera.
 67 
 68 	@param {Array} axisVec
 69 	@param {float} angle in radians.
 70 */
 71 c3dl.FreeCamera.prototype.rotateOnAxis = function(axisVec, angle)
 72 {
 73 	if ( !c3dl.isValidVector(axisVec) )
 74 	{
 75 		c3dl.debug.logWarning('FreeCamera::rotateOnAxis() called with the first parameter not a vector');
 76 		return;
 77 	}
 78 	if (isNaN(angle))
 79 	{
 80 		c3dl.debug.logWarning('FreeCamera::rotateOnAxis() called with the second parameter not a number');
 81 		return;
 82 	}
 83 	
 84 	// Create a proper Quaternion based on location and angle
 85 	var quat = c3dl.axisAngleToQuat(axisVec, angle);
 86 	
 87 	// Create a rotation Matrix out of this quaternion
 88 	var mat = c3dl.quatToMatrix(quat);
 89 		
 90 	// Apply changes to the remaining vectors
 91 	c3dl.multiplyMatrixByVector(mat, this.dir, this.dir);
 92 	c3dl.normalizeVector(this.dir);
 93 
 94 	c3dl.multiplyMatrixByVector(mat, this.left, this.left);
 95 	c3dl.normalizeVector(this.left);
 96 
 97 	c3dl.multiplyMatrixByVector(mat, this.up, this.up);
 98 	c3dl.normalizeVector(this.up);
 99 }
100 
101 
102 /**
103 	Set a new Angular Veclocity that will be added to the rotation on 
104 	every update.
105 
106 	@param {Array} newVec
107 */
108 c3dl.FreeCamera.prototype.setAngularVel = function(newVec)
109 {
110 	if (c3dl.isValidVector(newVec))
111 	{			
112 		this.angVel = c3dl.makeVector(newVec[0], newVec[1], newVec[2]);
113 	}
114 	else
115 	{
116 		c3dl.debug.logWarning('FreeCamera::setAngularVel() called with a parameter that\'s not a vector');
117 	}
118 }
119 
120 
121 /**
122 	Set a new linear velocity that will be added to the position 
123 	on every update.
124 
125 	@param {Array} newVec A vector which contains the direction 
126 	and speed of the camera.
127 */
128 c3dl.FreeCamera.prototype.setLinearVel = function(newVec)
129 {
130 	if (c3dl.isValidVector(newVec))
131 	{			
132 		this.linVel = c3dl.makeVector(newVec[0], newVec[1], newVec[2]);
133 	}
134 	else
135 	{
136 		c3dl.debug.logWarning('FreeCamera::setLinearVel() called with a parameter that\'s not a vector');
137 	}
138 }
139 
140 
141 /**
142 	Set the point in space where the camera will look at 
143 	(No Animation).
144 
145 	@param {Array} newVec The new point the camera will 
146 	look at.
147 */
148 c3dl.FreeCamera.prototype.setLookAtPoint = function(newVec)
149 {
150 	if (c3dl.isValidVector(newVec))
151 	{
152 		// if the position hasn't yet been changed and they want the
153 		// camera to look at [0,0,0], that will create a problem.
154 		if(c3dl.isVectorEqual(this.pos,[0,0,0]) && c3dl.isVectorEqual(newVec,[0,0,0]))
155 		{
156 			c3dl.debug.logWarning("Cannot lookAt [0,0,0] since camera is at [0,0,0]." + 
157 									" Move camera before calling setLookAt()");
158 		}
159 		else
160 		{			
161 			// Figure out the direction of the point we are looking at.
162 			this.dir = c3dl.subtractVectors( newVec,this.pos);
163 			c3dl.normalizeVector(this.dir);
164 
165 			// Adjust the Up and Left vectors accordingly
166 			c3dl.vectorCrossProduct([0,1,0],this.dir, this.left);
167 			c3dl.normalizeVector(this.left);
168 			c3dl.vectorCrossProduct(this.dir, this.left, this.up);
169 			c3dl.normalizeVector(this.up);
170 		}
171 	}
172 	else
173 	{
174 		c3dl.debug.logWarning("FreeCamera::setLookAtPoint() called with a parameter that's not a vector");
175 	}
176 }
177 
178 
179 /**
180 	Set the new location of the camera.
181 
182 	@param {Array} newVec An absolute value of where to 
183 	place the camera.
184 */
185 c3dl.FreeCamera.prototype.setPosition = function(newVec)
186 {
187 	if (c3dl.isValidVector(newVec))
188 	{
189 		// Set the new Position of the eye
190 		this.pos = newVec;
191 	}
192 	else
193 	{
194 		c3dl.debug.logWarning("FreeCamera::setPosition() called with a parameter that's not a vector");
195 	}
196 }
197 
198 
199 /**
200 	Set the orientation of Up (No Animation).
201 
202 	@param {Array} newVec
203 */
204 c3dl.FreeCamera.prototype.setUpVector = function(newVec)
205 {
206 	if (c3dl.isValidVector(newVec))
207 	{
208 		this.up = c3dl.makeVector(newVec[0], newVec[1], newVec[2]);
209 	}
210 	else
211 	{
212 		c3dl.debug.logWarning('FreeCamera::setUpVector() called with a parameter that\'s not a vector');
213 	}
214 }
215 
216 
217 /**
218 	Get a string representation of this camera.
219 	
220 	@param {null|String} delimiter A string which will separate values. Typically will be 
221 	","  ,  "\n" or "<br />". If none is specified, "," will be used.
222 
223 	@returns {String} a string representation of this camera.
224 */
225 c3dl.FreeCamera.prototype.toString = function(delimiter)
226 {
227 	// make sure user passed up a string if they actually decided
228 	// to specify a delimiter.
229 	if(!delimiter || typeof(delimiter) != "string")
230 	{
231 		delimiter = ",";
232 	}
233 
234 	// get the c3dl.Camera's toString()
235 	var cameraToStr = c3dl._super(this, arguments, "toString");
236 	
237 	var FreeCameraToStr =	"c3dl.FreeCamera: "		+ delimiter +		
238 							"angular velocity = "	+ this.getAngularVel() + delimiter +
239 							"linear velocity = "	+ this.getLinearVel() + delimiter;
240 
241 	return cameraToStr + FreeCameraToStr;
242 }
243 
244 
245 /**
246 	@private
247 	
248 	Called automatically.
249 
250 	Update Animation of the camera.
251 
252 	@param {float} timeStep 
253 */
254 c3dl.FreeCamera.prototype.update = function(timeStep)
255 {
256 	//
257 	if (c3dl.isVectorZero(this.linVel) && c3dl.isVectorZero(this.angVel))
258 	{
259 		return false;
260 	}
261 	
262 	if (c3dl.vectorLengthSq(this.linVel) > 0.0)
263 	{
264 		// Add a velocity to the position
265 		var velVec = c3dl.makeVector(this.linVel[0], this.linVel[1], this.linVel[2]);
266 		c3dl.multiplyVector(velVec, timeStep, velVec);
267 		
268 		c3dl.addVectors(this.pos, velVec, this.pos);
269 	}
270 	
271 	if (c3dl.vectorLengthSq(this.angVel) > 0.0)
272 	{
273 		// Apply some rotations to the orientation from the angular velocity
274 		this.pitch(this.angVel[0] * timeStep);
275 		this.yaw(this.angVel[1] * timeStep);
276 		this.roll(this.angVel[2] * timeStep);
277 	}
278 }
279 
280 
281 /**
282 	Rotate around the Up Vector by a hard amount (No Animation).
283 
284 	@param {float} angle in radians.
285 */
286 c3dl.FreeCamera.prototype.yaw = function(angle)
287 {
288 	this.rotateOnAxis(this.up, angle);
289 }
290