#region Copyright /* -------------------------------------------------------------------------------- This source file is part of Xenocide by Project Xenocide Team For the latest info on Xenocide, see http://www.projectxenocide.com/ This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.5/ or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA. -------------------------------------------------------------------------------- */ /* * @file GeoscapeScene.cs * @date Created: 2007/01/25 * @author File creator: dteviot * @author Credits: none */ #endregion #region Using Statements using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; using System.Drawing; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Content; using ProjectXenocide.Model.Geoscape; #endregion namespace ProjectXenocide.UI.Scenes.Common { /// /// Base class for a scene that shows a 3D model with a camera that moves /// in polar co-ordinates. I.e. scene has single 3D model, with camera /// that "revolves" around the model. e.g. Geoscape, XNet, Human Base /// public abstract class PolarScene { /// /// Constructor /// /// Initial position of camera in scene protected PolarScene(Vector3 cameraPosition) { this.cameraPosition = cameraPosition; } /// /// Constructor /// /// Initial distance of camera from origin protected PolarScene(float cameraDistance) : this(new Vector3(0.0f, 0.0f, cameraDistance)) { } /// /// Load the graphic content of the scene /// /// content manager that fetches the content /// the display public abstract void LoadContent(ContentManager content, GraphicsDevice device); /// /// Render scene /// /// time increment to use for updating scene /// Device to use for render /// Where to draw the scene on the display public abstract void Draw(GameTime gameTime, GraphicsDevice device, CeGui.Rect sceneWindow); /// /// Rotate the camera around the model /// /// Number of radians to move the camera in the Y-Z plane /// Number of radians to move the camera in the X-Z plane public virtual void RotateCamera(float longitude, float latitude) { cameraPosition.X += longitude; cameraPosition.Y += latitude; // don't rotate more than +/- 180 degrees while (Math.PI < cameraPosition.X) { cameraPosition.X -= (float)(2 * Math.PI); } while (cameraPosition.X < -Math.PI) { cameraPosition.X += (float)(2 * Math.PI); } // don't go up/down more than 85 degrees float clip = (float)(Math.PI * (0.5 * 85.0 / 90.0)); if (clip < cameraPosition.Y) { cameraPosition.Y = clip; } if (cameraPosition.Y < -clip) { cameraPosition.Y = -clip; } } /// /// Move the camera towards (or away) from the model /// /// Distance to move the camera public void ZoomCamera(float distance) { cameraPosition.Z += distance * (CameraHeight + 0.01f); // don't let the camera go inside the earth (earth's radius is 1) if (cameraPosition.Z < MinZoom) { cameraPosition.Z = MinZoom; } // don't want camera to go too far away either if (MaxZoom < cameraPosition.Z) { cameraPosition.Z = MaxZoom; } } /// /// Compute the projection matrix for the scene /// /// window's aspect ratio /// The calculated projection matrix protected static Matrix GetProjectionMatrix(float aspectRatio) { return Matrix.CreatePerspectiveFieldOfView( ViewAngle, aspectRatio, nearClipPlane, farClipPlane); } /// /// convert Window's co-ordinates to viewport co-ordinates /// /// Window co-ords to translate /// The current viewport /// Viewport co-ordinates protected Viewport CalcViewportForSceneWindow(CeGui.Rect windowCoords, Viewport viewport) { int fullHeight = viewport.Height; int fullWidth = viewport.Width; viewport.X = (int)(fullWidth * windowCoords.Left); viewport.Y = (int)(fullHeight * windowCoords.Top); viewport.Width = (int)(fullWidth * windowCoords.Width); viewport.Height = (int)(fullHeight * windowCoords.Height); // compute the aspect ratio while we're about it aspectRatio = (float)viewport.Width / (float)viewport.Height; return viewport; } #region Fields /// /// The position of the camera, in polar co-ordinates. /// public Vector3 CameraPosition { get { return cameraPosition; } set { GeoPosition.CheckBounds(value.X, value.Y); Debug.Assert((MinZoom <= value.Z) && (value.Z <= MaxZoom)); cameraPosition = value; } } /// /// The position of the camera, in polar co-ordinates. /// private Vector3 cameraPosition; /// /// Returns normalized height of the camera in [0, 1] range. /// public float CameraHeight { get { return (cameraPosition.Z - MinZoom) / (MaxZoom - MinZoom); } } /// /// The viewport's aspect ratio /// protected float AspectRatio { get { return aspectRatio; } } /// /// The viewport's aspect ratio /// private float aspectRatio; /// /// Maximum distance camera can be from the origin /// protected virtual float MaxZoom { get { return 5.0f; } } /// /// Minimum distance camera can be from the origin /// protected virtual float MinZoom { get { return 1.0f + nearClipPlane + 0.05f; } } #endregion #region Constant definitions /// /// Used in constructing viewing fustrum /// private const float nearClipPlane = 0.1f; /// /// Used in constructing viewing fustrum /// private const float farClipPlane = 20.0f; /// /// Used in constructing viewing fustrum /// protected const float ViewAngle = (float)Math.PI / 4.0f; // 45 degres #endregion } }