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