PageRenderTime 124ms CodeModel.GetById 61ms app.highlight 10ms RepoModel.GetById 50ms app.codeStats 0ms

/Rendering/Cameras/IsometricCamera.cs

#
C# | 309 lines | 201 code | 29 blank | 79 comment | 3 complexity | 3bca0f1809aee0ff9686213752405e59 MD5 | raw file
  1using System;
  2using System.IO;
  3using Delta.Engine;
  4using Delta.InputSystem;
  5using Delta.Utilities;
  6using Delta.Utilities.Datatypes;
  7using Delta.Utilities.Helpers;
  8using NUnit.Framework;
  9
 10namespace Delta.Rendering.Cameras
 11{
 12	/// <summary>
 13	/// 3D isometric perspective camera which works as LookAtCamera and has its 
 14	/// target but the different is that it has isometric projection.
 15	/// </summary>
 16	public class IsometricCamera : 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 Move speed Per Second.
 26		/// </summary>
 27		private const float MPS = 100.0f;
 28		#endregion
 29
 30		#region Position (Public)
 31		/// <summary>
 32		/// The camera position
 33		/// </summary>
 34		public override Vector Position
 35		{
 36			get
 37			{
 38				return position;
 39			}
 40			set
 41			{
 42				position = value;
 43				Target = position + (lookDirection * distance);
 44			}
 45		}
 46		#endregion
 47
 48		#region Target (Public)
 49		/// <summary>
 50		/// The camera target position.
 51		/// </summary>
 52		public override Vector Target
 53		{
 54			get
 55			{
 56				return target;
 57			}
 58			set
 59			{
 60				target = value;
 61				position = target - (lookDirection * distance);
 62			}
 63		}
 64		#endregion
 65
 66		#region Distance (Public)
 67		/// <summary>
 68		/// The distance between target position and camera position.
 69		/// </summary>
 70		public override float Distance
 71		{
 72			get
 73			{
 74				return distance;
 75			}
 76			set
 77			{
 78				// The effect of the distance is invariant for the IsometricCamera
 79				// because it uses orthographics projection so we actually "fake"
 80				// the behavior of zooming/unzooming by scaling the whole world
 81
 82				// only positive values are accepted for distance!
 83				if (value > 0.0f)
 84				{
 85					distance = value;
 86
 87					// update the camera position
 88					position = target - (lookDirection * distance);
 89
 90					// the larger the distance, the lower the scaling
 91					// + some additional adjustment
 92					scale = Matrix.CreateScale(distance);
 93				}
 94			}
 95		}
 96		#endregion
 97
 98		#region LookDirection (Public)
 99		/// <summary>
100		/// override the look direction to prevent the set accessor is making
101		/// bad stuff. An isometric camera always have the same lookdirection,
102		/// which is set in the constructor.
103		/// </summary>
104		public override Vector LookDirection
105		{
106			get
107			{
108				return lookDirection;
109			}
110			set
111			{
112			}
113		}
114		#endregion
115
116		#region Private
117
118		#region scale (Private)
119		/// <summary>
120		/// Scaling that emulates the Distance property for the isometric camera
121		/// </summary>
122		private Matrix scale;
123		#endregion
124
125		#endregion
126
127		#region Constructors
128		/// <summary>
129		/// Create isometric camera
130		/// </summary>
131		/// <param name="setPosition">Camera initial position.</param>
132		public IsometricCamera(Vector setPosition)
133			: base(setPosition)
134		{
135			lookDirection = new Vector(1, 1, -1);
136			// Set some default values
137			Distance = 1f;
138		}
139		#endregion
140
141		#region Zoom (Public)
142		/// <summary>
143		/// Zoom in or out. if respectFPS is set to true, Time.Delta will be taken
144		/// into account. E.g.: set this to true for hold-able buttons.
145		/// </summary>
146		/// <param name="zoomIn">if set to <c>true</c> [zoom in].</param>
147		public void Zoom(bool zoomIn)
148		{
149			if (IsLocked)
150			{
151				return;
152			}
153			float zoomSpeed = MathHelper.Max(Distance, 0.1f) * 0.1f *
154			                  MPS * (Time.Delta * 10f);
155			// Limit zoomSpeed, else we get into millions too quickly
156			zoomSpeed = MathHelper.Min(zoomSpeed, 10 * Time.Delta);
157			Distance += zoomIn
158			            	? -zoomSpeed
159			            	: zoomSpeed;
160		}
161		#endregion
162
163		#region UpdateProjectionMatrix (Public)
164		/// <summary>
165		/// Update projection matrix
166		/// </summary>
167		public override void UpdateProjectionMatrix()
168		{
169			// isometric uses an orthographic projection.
170			float halfWidth = Application.Window.ViewportPixelWidth;
171			float halfHeight = Application.Window.ViewportPixelHeight;
172			projectionMatrix = Matrix.CreateOrthographic(-halfWidth, halfWidth,
173				halfHeight, -halfHeight, NearPlane, FarPlane);
174		}
175		#endregion
176
177		#region Save (Public)
178		/// <summary>
179		/// Override saving data from BinaryStream.
180		/// </summary>
181		/// <param name="dataWriter">Binary writer used for writing data.</param>
182		public override void Save(BinaryWriter dataWriter)
183		{
184			base.Save(dataWriter);
185
186			// Save the implementation version first
187			dataWriter.Write(ImplementationVersion);
188
189			// just need to save the scale matrix here
190			scale.Save(dataWriter);
191		}
192		#endregion
193
194		#region Load (Public)
195		/// <summary>
196		/// Override loading data from BinaryStream.
197		/// </summary>
198		/// <param name="reader">Binary reader used for reading data.</param>
199		public override void Load(BinaryReader reader)
200		{
201			base.Load(reader);
202
203			// First read the implementation version
204			int version = reader.ReadInt32();
205			switch (version)
206			{
207					// Version 1
208				case 1:
209					// Need just to read the scale matrix here
210					scale.Load(reader);
211					break;
212
213				default:
214					Log.InvalidVersionWarning(GetType().Name + ": " + Name,
215						version, ImplementationVersion);
216					break;
217			}
218		}
219		#endregion
220
221		#region Methods (Private)
222
223		#region SetupInputCommands
224		/// <summary>
225		/// Setup the connection between input commands and camera movement.
226		/// </summary>
227		protected override void SetupInputCommands()
228		{
229			#region Zoom
230			Input.Commands[Command.CameraZoomIn].Add(delegate
231			{
232				Zoom(true);
233			});
234			Input.Commands[Command.CameraZoomOut].Add(delegate
235			{
236				Zoom(false);
237			});
238			#endregion
239		}
240		#endregion
241
242		#region UpdateViewMatrix
243		protected override void UpdateViewMatrix()
244		{
245			base.UpdateViewMatrix();
246		}
247		#endregion
248
249		#endregion
250
251		/// <summary>
252		/// Tests
253		/// </summary>
254		internal class IsometricCameraTests
255		{
256			#region TestSaveAndLoad (LongRunning)
257			/// <summary>
258			/// Test save and load functionality of the Graph class
259			/// </summary>
260			[Test, Category("LongRunning")]
261			public void TestSaveAndLoad()
262			{
263				// Creation of the graph
264				IsometricCamera isoCamera = new IsometricCamera(new Vector(3, -6, 8))
265				{
266					// BaseCamera
267					LookDirection = new Vector(-1, 2, -1),
268					Target = new Vector(3, 4, 1),
269					Rotation = new Vector(3, 1, 0),
270					FieldOfView = 65,
271					FarPlane = 205,
272					NearPlane = 0.15f,
273					AlwaysNeedsUpdate = true,
274					IsLocked = true,
275					// IsometricCamera
276					scale = Matrix.CreateScale(0.3f, 1.4f, 0.58f),
277				};
278
279				// Saving
280				MemoryStream savedStream = new MemoryStream();
281				BinaryWriter writer = new BinaryWriter(savedStream);
282				isoCamera.Save(writer);
283				writer.Flush();
284				writer = null;
285
286				// Loading
287				savedStream.Position = 0;
288				BinaryReader reader = new BinaryReader(savedStream);
289				IsometricCamera loadedCamera = new IsometricCamera(Vector.Zero);
290				loadedCamera.Load(reader);
291
292				// Checking
293				// BaseCamera values
294				Assert.Equal(loadedCamera.LookDirection, isoCamera.LookDirection);
295				Assert.Equal(loadedCamera.Target, isoCamera.Target);
296				Assert.Equal(loadedCamera.Rotation, isoCamera.Rotation);
297				Assert.Equal(loadedCamera.FieldOfView, isoCamera.FieldOfView);
298				Assert.Equal(loadedCamera.FarPlane, isoCamera.FarPlane);
299				Assert.Equal(loadedCamera.NearPlane, isoCamera.NearPlane);
300				Assert.Equal(loadedCamera.AlwaysNeedsUpdate,
301					isoCamera.AlwaysNeedsUpdate);
302				Assert.Equal(loadedCamera.IsLocked, isoCamera.IsLocked);
303				// IsometricCamera values
304				Assert.Equal(loadedCamera.scale, isoCamera.scale);
305			}
306			#endregion
307		}
308	}
309}