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

/Rendering/Cameras/FreeCamera.cs

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