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

/Rendering/Cameras/IsoPerspectiveCamera.cs

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