PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Rendering/Cameras/IsometricCamera.cs

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