PageRenderTime 94ms CodeModel.GetById 60ms app.highlight 11ms RepoModel.GetById 20ms app.codeStats 0ms

/Rendering/Cameras/IsoPerspectiveCamera.cs

#
C# | 292 lines | 185 code | 30 blank | 77 comment | 2 complexity | 499a73a8321c17cdfa4a821ab2d867ed MD5 | raw file
  1using System;
  2using System.IO;
  3using Delta.Engine;
  4using Delta.Utilities;
  5using Delta.Utilities.Datatypes;
  6using NUnit.Framework;
  7
  8namespace Delta.Rendering.Cameras
  9{
 10	/// <summary>
 11	/// 3D Iso perspective camera which works as LookAtCamera and has its target
 12	/// but the different is that it has iso-perspective projection.
 13	/// </summary>
 14	public class IsoPerspectiveCamera : BaseCamera
 15	{
 16		#region Constants
 17		/// <summary>
 18		/// The current version of the implementation of this Camera class.
 19		/// </summary>
 20		private const int ImplementationVersion = 1;
 21		#endregion
 22
 23		#region Position (Public)
 24		/// <summary>
 25		/// The camera position.
 26		/// </summary>
 27		public override Vector Position
 28		{
 29			get
 30			{
 31				return position;
 32			}
 33			set
 34			{
 35				position = value;
 36				target = position - (LookDirection * Distance);
 37			}
 38		}
 39		#endregion
 40
 41		#region Target (Public)
 42		/// <summary>
 43		/// The camera target position
 44		/// </summary>
 45		public override Vector Target
 46		{
 47			get
 48			{
 49				return target;
 50			}
 51			set
 52			{
 53				target = value;
 54				position = target + (LookDirection * Distance);
 55			}
 56		}
 57		#endregion
 58
 59		#region Distance (Public)
 60		/// <summary>
 61		/// The distance between target position and camera position.
 62		/// </summary>
 63		public override float Distance
 64		{
 65			get
 66			{
 67				return distance;
 68			}
 69			set
 70			{
 71				// The effect of the distance is invariant for the IsometricCamera
 72				// because it uses orthographics projection so we actually "fake"
 73				// the behavior of zooming/unzooming by scaling the whole world
 74
 75				// only positive values are accepted for distance!
 76				if (value > 0.0f)
 77				{
 78					distance = value;
 79
 80					// update the camera position
 81					position = target + (LookDirection * distance);
 82
 83					// the larger the distance, the lower the scaling
 84					// + some additional adjustment
 85					scale = Matrix.CreateScale(100.0f / distance);
 86				}
 87			}
 88		}
 89		#endregion
 90
 91		#region LookDirection (Public)
 92		/// <summary>
 93		/// The look direction.
 94		/// </summary>
 95		public override Vector LookDirection
 96		{
 97			get
 98			{
 99				return lookDirection;
100			}
101			set
102			{
103			}
104		}
105		#endregion
106
107		#region Private
108
109		#region scale (Private)
110		/// <summary>
111		/// Scaling that emulates the Distance property for the isometric camera
112		/// </summary>
113		private Matrix scale;
114		#endregion
115
116		#region cameraShake (Private)
117		/// <summary>
118		/// The shake value
119		/// </summary>
120		private Vector cameraShake;
121		#endregion
122
123		#endregion
124
125		#region Constructors
126		/// <summary>
127		/// Create iso perspective camera
128		/// </summary>
129		/// <param name="setPosition">Set position</param>
130		public IsoPerspectiveCamera(Vector setPosition)
131			: base(setPosition)
132		{
133			lookDirection = new Vector(1, 1, -1);
134			// Set some default values
135			Distance = 1f;
136			cameraShake = Vector.Zero;
137		}
138		#endregion
139
140		#region Shake (Public)
141		/// <summary>
142		/// Shake
143		/// </summary>
144		/// <param name="amount">The amount.</param>
145		public void Shake(float amount)
146		{
147			cameraShake.Z = amount;
148		}
149		#endregion
150
151		#region Save (Public)
152		/// <summary>
153		/// Override saving data from BinaryStream.
154		/// </summary>
155		/// <param name="dataWriter">Binary writer used for writing data.</param>
156		public override void Save(BinaryWriter dataWriter)
157		{
158			base.Save(dataWriter);
159
160			// Save the implementation version
161			dataWriter.Write(ImplementationVersion);
162
163			// just need to save the scale matrix here
164			scale.Save(dataWriter);
165		}
166		#endregion
167
168		#region Load (Public)
169		/// <summary>
170		/// Override loading data from BinaryStream.
171		/// </summary>
172		/// <param name="reader">Binary reader used for reading data.</param>
173		public override void Load(BinaryReader reader)
174		{
175			base.Load(reader);
176
177			// We currently only support our version, if more versions are added,
178			// we need to do different loading code depending on the version here.
179			int version = reader.ReadInt32();
180			switch (version)
181			{
182					// Version 1
183				case 1:
184					// Need just to read the scale matrix here
185					scale.Load(reader);
186					break;
187
188				default:
189					Log.InvalidVersionWarning(GetType().Name + ": " + Name,
190						version, ImplementationVersion);
191					break;
192			} // switch
193		}
194		#endregion
195
196		#region Methods (Private)
197
198		#region UpdateViewMatrix
199		/// <summary>
200		/// Update view matrix
201		/// </summary>
202		protected override void UpdateViewMatrix()
203		{
204			// isometric uses a simple look at view.
205			viewMatrix = Matrix.CreateLookAt(Position + cameraShake, Target,
206				Vector.UnitZ);
207			Matrix.Multiply(ref viewMatrix, ref scale, ref viewMatrix);
208		}
209		#endregion
210
211		#region InternalRun
212		/// <summary>
213		/// Updates the camera
214		/// </summary>
215		protected override void InternalRun()
216		{
217
218			// slowly decrease the camera shaking value unti we reach zero.
219			cameraShake.Z = (cameraShake.Z > 0)
220			                	? +
221			                	  cameraShake.Z - Time.Delta * 4f
222			                	: 0f;
223
224			base.InternalRun();
225		}
226		#endregion
227
228		#endregion
229
230		/// <summary>
231		/// Tests
232		/// </summary>
233		internal class IsoPerspectiveTests
234		{
235			#region TestSaveAndLoad (LongRunning)
236			/// <summary>
237			/// Test save and load functionality of the Graph class
238			/// </summary>
239			[Test, Category("LongRunning")]
240			public void TestSaveAndLoad()
241			{
242				// Creation of the graph
243				IsoPerspectiveCamera isoPerspectiveCamera =
244					new IsoPerspectiveCamera(new Vector(3, -6, 8))
245					{
246						// BaseCamera
247						LookDirection = new Vector(-1, 2, -1),
248						Target = new Vector(3, 4, 1),
249						Rotation = new Vector(3, 1, 0),
250						FieldOfView = 65,
251						FarPlane = 205,
252						NearPlane = 0.15f,
253						AlwaysNeedsUpdate = true,
254						IsLocked = true,
255						// IsoPerspectiveCamera
256						scale = Matrix.CreateScale(0.3f, 1.4f, 0.58f),
257					};
258
259				// Saving
260				MemoryStream savedStream = new MemoryStream();
261				BinaryWriter writer = new BinaryWriter(savedStream);
262				isoPerspectiveCamera.Save(writer);
263				writer.Flush();
264				writer = null;
265
266				// Loading
267				savedStream.Position = 0;
268				BinaryReader reader = new BinaryReader(savedStream);
269				IsoPerspectiveCamera loadedCamera =
270					new IsoPerspectiveCamera(Vector.Zero);
271				loadedCamera.Load(reader);
272
273				// Checking
274				// BaseCamera values
275				Assert.Equal(loadedCamera.LookDirection,
276					isoPerspectiveCamera.LookDirection);
277				Assert.Equal(loadedCamera.Target, isoPerspectiveCamera.Target);
278				Assert.Equal(loadedCamera.Rotation, isoPerspectiveCamera.Rotation);
279				Assert.Equal(loadedCamera.FieldOfView,
280					isoPerspectiveCamera.FieldOfView);
281				Assert.Equal(loadedCamera.FarPlane, isoPerspectiveCamera.FarPlane);
282				Assert.Equal(loadedCamera.NearPlane, isoPerspectiveCamera.NearPlane);
283				Assert.Equal(loadedCamera.AlwaysNeedsUpdate,
284					isoPerspectiveCamera.AlwaysNeedsUpdate);
285				Assert.Equal(loadedCamera.IsLocked, isoPerspectiveCamera.IsLocked);
286				// IsoPerspectiveCamera values
287				Assert.Equal(loadedCamera.scale, isoPerspectiveCamera.scale);
288			}
289			#endregion
290		}
291	}
292}