PageRenderTime 135ms CodeModel.GetById 51ms app.highlight 15ms RepoModel.GetById 65ms app.codeStats 0ms

/Rendering/Cameras/FreeCamera.cs

#
C# | 467 lines | 283 code | 44 blank | 140 comment | 19 complexity | 9d2f174c66c2ac7023f14df6f48fe835 MD5 | raw file
  1using System.IO;
  2using Delta.Engine;
  3using Delta.InputSystem;
  4using Delta.InputSystem.Devices;
  5using Delta.Utilities;
  6using Delta.Utilities.Datatypes;
  7using NUnit.Framework;
  8
  9namespace Delta.Rendering.Cameras
 10{
 11	/// <summary>
 12	/// Free camera. This camera is useful to look around in the game scene.
 13	/// Move and rotate the camera as you want with any input device. Not really
 14	/// used much in games, but useful for debugging or observing.
 15	/// </summary>
 16	public class FreeCamera : BaseCamera
 17	{
 18		#region Constants
 19		/// <summary>
 20		/// The current version of the implementation of this Camera class.
 21		/// </summary>
 22		private const int ImplementationVersion = 1;
 23
 24		/// <summary>
 25		/// The default move speed per second.
 26		/// </summary>
 27		private const float MPS = 100.0f;
 28
 29		/// <summary>
 30		/// Speed multiplier for mouse control
 31		/// </summary>
 32		private const float MouseSpeedFactor = 2.75f;
 33
 34		/// <summary>
 35		/// Speed multiplier for keyboard control
 36		/// </summary>
 37		private const float KeyboardSpeedFactor = 1.0f;
 38
 39		/// <summary>
 40		/// Limit for looking downwards
 41		/// </summary>
 42		private const float MinPitchRotation = -90 + 1; //2;
 43
 44		/// <summary>
 45		/// Limit for looking upwards
 46		/// </summary>
 47		private const float MaxPitchRotation = +90 - 1; //2;
 48
 49		/// <summary>
 50		/// A default position which can be used if the current camera position
 51		/// value isn't known (in the constructor).
 52		/// </summary>
 53		public static readonly Vector DefaultLookAtCamPosition =
 54			new Vector(0.0f, -5.0f, 5.0f);
 55
 56		/// <summary>
 57		/// A position to a default target twhich can be used if the current camera
 58		/// target position value isn't known (in the constructor).
 59		/// </summary>
 60		public static readonly Vector DefaultTargetPosition = Vector.Zero;
 61		#endregion
 62
 63		#region Pitch (Public)
 64		/// <summary>
 65		/// Pitch
 66		/// </summary>
 67		public float Pitch
 68		{
 69			get;
 70			set;
 71		}
 72		#endregion
 73
 74		#region Yaw (Public)
 75		/// <summary>
 76		/// Yaw
 77		/// </summary>
 78		public float Yaw
 79		{
 80			get;
 81			set;
 82		}
 83		#endregion
 84
 85		#region Roll (Public)
 86		/// <summary>
 87		/// Roll
 88		/// </summary>
 89		public float Roll
 90		{
 91			get;
 92			set;
 93		}
 94		#endregion
 95
 96		#region IsStopMoving (Public)
 97		/// <summary>
 98		/// Flag for preventing the camera from moving.
 99		/// </summary>
100		public bool IsStopMoving
101		{
102			get;
103			set;
104		}
105		#endregion
106
107		#region MovementSpeed (Public)
108		public float MovementSpeed
109		{
110			get;
111			set;
112		}
113		#endregion
114
115		#region Private
116
117		#region rotationMatrix (Private)
118		/// <summary>
119		/// Rotation matrix, will be computed automatically by the (Internal)Run()
120		/// method.
121		/// </summary>
122		private Matrix rotationMatrix;
123		#endregion
124
125		#region UpDirection (Private)
126		/// <summary>
127		/// Up direction
128		/// </summary>
129		private Vector UpDirection
130		{
131			get;
132			set;
133		}
134		#endregion
135
136		#region RightDirection (Private)
137		/// <summary>
138		/// Right direction
139		/// </summary>
140		private Vector RightDirection
141		{
142			get;
143			set;
144		}
145		#endregion
146
147		#endregion
148
149		#region Constructors
150		/// <summary>
151		/// Create free camera
152		/// </summary>
153		/// <param name="setPosition">Camera initial position.</param>
154		public FreeCamera(Vector setPosition)
155			: base(setPosition)
156		{
157			// Default look direction for this camera.
158			LookDirection = Vector.UnitY;
159			UpDirection = UpVector; // Vector.UnitZ;
160			RightDirection = Vector.UnitX;
161			MovementSpeed = 2.5f;
162		}
163		#endregion
164
165		#region MoveUp (Public)
166		/// <summary>
167		/// Moves the camera up.
168		/// </summary>
169		/// <param name="moveVelocity">The move velocity.</param>
170		public void MoveUp(float moveVelocity)
171		{
172			Position += UpDirection * moveVelocity;
173		}
174		#endregion
175
176		#region MoveDown (Public)
177		/// <summary>
178		/// Move the camera down.
179		/// </summary>
180		/// <param name="moveVelocity">Move velocity.</param>
181		public void MoveDown(float moveVelocity)
182		{
183			Position -= UpDirection * moveVelocity;
184		}
185		#endregion
186
187		#region MoveRight (Public)
188		/// <summary>
189		/// Move the camera right.
190		/// </summary>
191		/// <param name="moveVelocity">Move velocity.</param>
192		public void MoveRight(float moveVelocity)
193		{
194			Position += RightDirection * moveVelocity;
195		}
196		#endregion
197
198		#region MoveLeft (Public)
199		/// <summary>
200		/// Move the camera left.
201		/// </summary>
202		/// <param name="moveVelocity">Move velocity.</param>
203		public void MoveLeft(float moveVelocity)
204		{
205			Position -= RightDirection * moveVelocity;
206		}
207		#endregion
208
209		#region MoveForward (Public)
210		/// <summary>
211		/// Move the camera forward.
212		/// </summary>
213		/// <param name="moveVelocity">Move velocity.</param>
214		public void MoveForward(float moveVelocity)
215		{
216			Position += LookDirection * moveVelocity;
217		}
218		#endregion
219
220		#region MoveBackward (Public)
221		/// <summary>
222		/// Move the camera backward.
223		/// </summary>
224		/// <param name="moveVelocity">Move velocity.</param>
225		public void MoveBackward(float moveVelocity)
226		{
227			Position -= LookDirection * moveVelocity;
228		}
229		#endregion
230
231		#region Save (Public)
232		/// <summary>
233		/// Override saving data from BinaryStream.
234		/// </summary>
235		/// <param name="dataWriter">Binary writer used for writing data.</param>
236		public override void Save(BinaryWriter dataWriter)
237		{
238			base.Save(dataWriter);
239
240			// Save the implementation version first
241			dataWriter.Write(ImplementationVersion);
242
243			// and then all required values
244			dataWriter.Write(Pitch);
245			dataWriter.Write(Yaw);
246			dataWriter.Write(Roll);
247
248			UpDirection.Save(dataWriter);
249			RightDirection.Save(dataWriter);
250		}
251		#endregion
252
253		#region Load (Public)
254		/// <summary>
255		/// Override loading data from BinaryStream.
256		/// </summary>
257		/// <param name="reader">Binary reader used for reading data.</param>
258		public override void Load(BinaryReader reader)
259		{
260			base.Load(reader);
261
262			// First read the implementation version
263			int version = reader.ReadInt32();
264			switch (version)
265			{
266					// Version 1
267				case 1:
268					// Now read just the saved values
269					Pitch = reader.ReadSingle();
270					Yaw = reader.ReadSingle();
271					Roll = reader.ReadSingle();
272
273					UpDirection = new Vector(reader);
274					RightDirection = new Vector(reader);
275					break;
276
277				default:
278					Log.InvalidVersionWarning(GetType().Name + ": " + Name,
279						version, ImplementationVersion);
280					break;
281			} // switch
282		}
283		#endregion
284
285		#region Methods (Private)
286
287		#region UpdateViewMatrix
288		/// <summary>
289		/// Update the view matrix.
290		/// </summary>
291		protected override void UpdateViewMatrix()
292		{
293			// one !?
294			viewMatrix = Matrix.CreateLookAt(Position, Position + LookDirection,
295				//wtf? -UpDirection);
296				UpDirection);
297		}
298		#endregion
299
300		//too buggy: Point lastTouchPosition = Point.Zero;
301
302		#region InternalRun
303		/// <summary>
304		/// Update the free camera.
305		/// </summary>
306		protected override void InternalRun()
307		{
308			//#if DISABLED
309			// Skip Input if the camera is locked!
310			if (IsLocked == false)
311			{
312				BaseTouch touch = Input.Touch;
313				BaseMouse mouse = Input.Mouse;
314				if (touch.IsConnected)
315				{
316					if (touch.TouchIsPressed)
317					{
318						/*tst
319						// Just always rotate
320						Roll += 5.0f;//5 degrees per frame MPS * relativePosition.X * MouseSpeedFactor;
321						Pitch += 0.5f;//0.5 degrees per frame.
322						*/
323						// * suxx
324						// Only dragging is supported right now ^^
325						//buggy?
326						Point relativePosition = touch.Position - touch.LastFramePosition;
327						//Point relativePosition = touch.Position - lastTouchPosition;
328						if (relativePosition != Point.Zero)
329						{
330							if (IsStopMoving == false)
331							{
332								Roll +=
333									//rotation.X -=
334									MPS * relativePosition.X * MouseSpeedFactor;
335								Pitch -=
336									//rotation.Y +=
337									MPS * relativePosition.Y * MouseSpeedFactor;
338							} // if
339							else
340							{
341								// If in stop moving mode, rotate light instead of camera
342								Light.RotateDirection(relativePosition * MPS *
343								                      MouseSpeedFactor);
344							}
345						} // if
346						if (IsStopMoving == false)
347						{
348							// Zoom a little into the scene
349							Position += LookDirection * MovementSpeed * Time.Delta;
350						}
351						// * /
352					} // if
353					//lastTouchPosition = touch.Position;
354				} // if
355				else if (mouse.LeftButtonIsPressed)
356				{
357					Point relativePosition = mouse.Position - mouse.LastFramePosition;
358					if (relativePosition != Point.Zero)
359					{
360						if (IsStopMoving == false)
361						{
362							Roll +=
363								//rotation.X -=
364								MPS * relativePosition.X * MouseSpeedFactor;
365							//rotation.Y +=
366							Pitch -=
367								MPS * relativePosition.Y * MouseSpeedFactor;
368						} // if
369						else
370						{
371							// If in stop moving mode, rotate light instead of camera
372							Light.RotateDirection(
373								relativePosition * MPS * MouseSpeedFactor);
374						}
375					} // if
376					if (IsStopMoving == false)
377					{
378						// Zoom a little into the scene
379						Position += LookDirection * MovementSpeed * Time.Delta;
380					}
381				} // else if
382			} // if
383			//#endif
384			rotationMatrix = Matrix.Identity;
385			Matrix xRotation = Matrix.CreateRotationX(Pitch);
386			Matrix yRotation = Matrix.CreateRotationY(Yaw);
387			Matrix zRotation = Matrix.CreateRotationZ(-Roll);
388			Matrix.Multiply(ref xRotation, ref yRotation, ref rotationMatrix);
389			Matrix.Multiply(ref rotationMatrix, ref zRotation, ref rotationMatrix);
390
391			LookDirection = Vector.TransformNormal(Vector.UnitY, rotationMatrix);
392			UpDirection = Vector.TransformNormal(UpVector, rotationMatrix);
393			RightDirection = Vector.TransformNormal(Vector.UnitX, rotationMatrix);
394
395			base.InternalRun();
396		}
397		#endregion
398
399		#endregion
400
401		/// <summary>
402		/// Tests
403		/// </summary>
404		internal class FreeCameraTests
405		{
406			#region TestSaveAndLoad (LongRunning)
407			/// <summary>
408			/// Test save and load functionality of the Graph class
409			/// </summary>
410			[Test, Category("LongRunning")]
411			public void TestSaveAndLoad()
412			{
413				// Creation of the graph
414				FreeCamera freeCamera = new FreeCamera(new Vector(3, -6, 8))
415				{
416					// BaseCamera
417					LookDirection = new Vector(-1, 2, -1),
418					Target = new Vector(3, 4, 1),
419					Rotation = new Vector(3, 1, 0),
420					FieldOfView = 65,
421					FarPlane = 205,
422					NearPlane = 0.15f,
423					AlwaysNeedsUpdate = true,
424					IsLocked = true,
425					// FreeCamera
426					Pitch = 3,
427					Yaw = 2,
428					Roll = 0.5f,
429					UpDirection = -Vector.UnitZ,
430					RightDirection = -Vector.UnitX,
431				};
432
433				// Saving
434				MemoryStream savedStream = new MemoryStream();
435				BinaryWriter writer = new BinaryWriter(savedStream);
436				freeCamera.Save(writer);
437				writer.Flush();
438				writer = null;
439
440				// Loading
441				savedStream.Position = 0;
442				BinaryReader reader = new BinaryReader(savedStream);
443				FreeCamera loadedCamera = new FreeCamera(Vector.Zero);
444				loadedCamera.Load(reader);
445
446				// Checking
447				// BaseCamera values
448				Assert.Equal(loadedCamera.LookDirection, freeCamera.LookDirection);
449				Assert.Equal(loadedCamera.Target, freeCamera.Target);
450				Assert.Equal(loadedCamera.Rotation, freeCamera.Rotation);
451				Assert.Equal(loadedCamera.FieldOfView, freeCamera.FieldOfView);
452				Assert.Equal(loadedCamera.FarPlane, freeCamera.FarPlane);
453				Assert.Equal(loadedCamera.NearPlane, freeCamera.NearPlane);
454				Assert.Equal(loadedCamera.AlwaysNeedsUpdate,
455					freeCamera.AlwaysNeedsUpdate);
456				Assert.Equal(loadedCamera.IsLocked, freeCamera.IsLocked);
457				// FreeCamera values
458				Assert.Equal(loadedCamera.Pitch, freeCamera.Pitch);
459				Assert.Equal(loadedCamera.Yaw, freeCamera.Yaw);
460				Assert.Equal(loadedCamera.Roll, freeCamera.Roll);
461				Assert.Equal(loadedCamera.UpDirection, freeCamera.UpDirection);
462				Assert.Equal(loadedCamera.RightDirection, freeCamera.RightDirection);
463			}
464			#endregion
465		}
466	}
467}