/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}