text: //////////////////////////////////////////////////////////////////////////////
  // Copyright (C) 2008-2014, Shane Liesegang
  // All rights reserved.
  // 
  // Redistribution and use in source and binary forms, with or without 
  // modification, are permitted provided that the following conditions are met:
  // 
  //     * Redistributions of source code must retain the above copyright 
  //       notice, this list of conditions and the following disclaimer.
  //     * Redistributions in binary form must reproduce the above copyright 
  //       notice, this list of conditions and the following disclaimer in the 
  //       documentation and/or other materials provided with the distribution.
  //     * Neither the name of the copyright holder nor the names of any 
  //       contributors may be used to endorse or promote products derived from 
  //       this software without specific prior written permission.
  // 
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  // POSSIBILITY OF SUCH DAMAGE.
  //////////////////////////////////////////////////////////////////////////////
  
  #pragma once
  
  #include "../Actors/Actor.h"
  #include "../Infrastructure/Vector3.h"
  
  #define theCamera Camera::GetInstance()
  
  ///The class that handles displaying the appropriate viewport.
  /** 
   * The Camera class is how you control what your players see at any time. 
   *  It uses the singleton pattern; you can't actually declare a new instance
   *  of a Camera. To access the Camera in your world, use "theCamera" to retrieve
   *  the singleton object. "theCamera" is defined in both C++ and Lua. 
   * 
   * If you're not familiar with the singleton pattern, this paper is a good 
   *  starting point. (Don't be afraid that it's written by Microsoft.)
   * 
   * http://msdn.microsoft.com/en-us/library/ms954629.aspx
   * 
   * Camera is an Actor so that you can apply motion to it the same way you would
   *  any other Actor in your world. 
   * 
   * By default the camera is positioned 10 units away from the origin, looking
   *  down the Z-axis (0.0, 0.0, 10.0). The visible world stretches from 
   *  (-13.3, -10) to (13.3, 10).
   * 
   * Whenever the Camera updates its position or the viewport, it broadcasts a 
   *  "CameraChange" Message that you can subscribe to if you need notifications. 
   */
  class Camera : public Actor 
  {
  public:
  	/**
  	 * Used to access the singleton instance of this class. As a shortcut, 
  	 *  you can just use "theCamera". 
  	 * 
  	 * @return The singleton
  	 */
  	static Camera &GetInstance();
  	
  	#if !ANGEL_MOBILE
  		/**
  		 * The callback used by GLFW to alert us when the user changes the size
  		 *  of the window. You shouldn't need to mess with this. 
  		 * 
  		 * @param w New width in pixels
  		 * @param h New height in pixels
  		 */
  		static void ResizeCallback(GLFWwindow* window, int w, int h);
  	#endif
  	
  	/**
  	 * Deletes and NULLs out the singleton -- should only get called at World
  	 *  destruction when the program is exiting. 
  	 */
  	void Destroy();
  	
  	/**
  	 * Override of actor's Update method to deal with the actor lock
  	 */
  	virtual void Update(float dt);
  	
  	/**
  	 * Makes sure the view matrix is properly set up on every frame. Called 
  	 *  by the world before rendering anything else. 
  	 */
  	virtual void Render();
  	
  	/**
  	 * Resets the viewport to its default. 
  	 */
  	void Reset();
  	
  	/**
  	 * Locks the camera to a specific Actor so it will track
  	 *  it around.
  	 *
  	 * @param locked The actor to track
  	 * @param lockX Whether to track the actor's X position
  	 * @param lockY Whether to track the actor's Y position
  	 * @param lockRotation Whether to track the actor's rotation
  	 */
  	void LockTo(Actor* locked, bool lockX=true, bool lockY=true, bool lockRotation=false);
  	
  	/**
  	 * Get the actor that the camera is currently tracking. 
  	 * 
  	 * @return The tracked actor (NULL if not tracking anything)
  	 */
  	Actor* GetLockedActor() { return _locked; }
  	
  	/**
  	 * Get the window's current height. 
  	 * 
  	 * @return Height in pixels. 
  	 */
  	const int GetWindowHeight() const;
  	
  	/**
  	 * Get the window's current width. 
  	 * 
  	 * @return Width in pixels.
  	 */
  	const int GetWindowWidth() const;
  	
  	/**
  	 * If you were to draw a circle inscribed in the viewport, this function
  	 *  will let you know the size of its radius. This is useful for determining
  	 *  how much of the world is currently being displayed. 
  	 * 
  	 * Note that if you have a non-square viewport, the circle is bounded by
  	 *  the \b smaller dimension.
  	 * 
  	 * @return The radius size in GL units. 
  	 */
  	const double GetViewRadius() const;
  	
  	/**
  	 * Get the world coordinate of the top-right point of the window. 
  	 * 
  	 * @return The world coordinate (GL units).
  	 */
  	const Vector2 GetWorldMaxVertex() const;
  	
  	/**
  	 * Get the world coordinate of the bottom-left point of the window. 
  	 * 
  	 * @return The world coordinate (GL units).
  	 */
  	const Vector2 GetWorldMinVertex() const;
  
  	/**
  	 * Set the position of the camera. Note that the camera is the only
  	 *  Actor that can take a Z coordinate for its position -- you can zoom
  	 *  in and out. 
  	 * 
  	 * @param x The new X position for the camera
  	 * @param y The new Y position for the camera
  	 * @param z The new Z position for the camera
  	 */
  	virtual void SetPosition(float x, float y, float z);
  	
  	/**
  	 * Set the position of the camera. Using this two-dimensional function,
  	 *  the position on the Z-axis stays fixed. 
  	 * 
  	 * @param x The new X position for the camera 
  	 * @param y The new Y position for the camera
  	 */
  	virtual void SetPosition(float x, float y);
  	
  	/**
  	 * Set the position of the camera. Note that the camera is the only
  	 *  Actor that can take a Z coordinate for its position -- you can zoom
  	 *  in and out. 
  	 *
  	 * @param v3 The new position for the camera. 
  	 */
  	virtual void SetPosition(const Vector3& v3);
  	
  	/**
  	 * Set the position of the camera. Using this two-dimensional function, 
  	 *  the position on the Z-axis stays fixed. 
  	 * 
  	 * @param v2 The new position for the Camera
  	 */
  	virtual void SetPosition(const Vector2& v2);
      
  	/**
  	 * Interval movement for the camera in three dimensions.
  	 * 
  	 * @see Actor::MoveTo
  	 * @param newPosition The target position for the movement
  	 * @param duration How long it should take to get there
  	 * @param smooth Whether the function should use MathUtil::SmoothStep
  	 *  instead of MathUtil::Lerp
  	 * @param onCompletionMessage If specified, a Message of this type will be
  	 *  sent when the movement is complete, letting you know when it's done.
  	 *  You will have to manually subscribe to this Message, though.
  	 */
  	virtual void MoveTo(const Vector3& newPosition, float duration, bool smooth=false, String onCompletionMessage="");
  	
  	/**
  	 * Get the position of the camera on the Z-axis. 
  	 * 
  	 * @return The camera's Z coordinate. 
  	 */
  	float GetZ() const;
  	
  	/**
  	 * Set the rotation of the camera. Only rotates about the Z-axis,
  	 *  since we prefer the 2-dimensional.
  	 * 
  	 * @param v2 The new rotation for the Camera. As with Actors, positive
  	 *   rotations are counter-clockwise.
  	 */
  	virtual void SetRotation(float rotation);
  	
  	/**
  	* Get the Z value necessary to achieve the requested view radius. 
  	* 
  	* @param radius The desired view radius.
  	* @return The Z value. 
  	*/
  	float GetZForViewRadius(float radius);
  
  	/**
  	* Get the near clip distance.
  	* 
  	* @return The near clip distance. 
  	*/
  	float GetNearClipDist();
  
  	/**
  	* Get the far clip distance.
  	* 
  	* @return The far clip distance. 
  	*/
  	float GetFarClipDist();
  
  	/**
  	* Set the Z value necessary to achieve the requested view radius. 
  	* 
  	* @param newRadius The desired view radius.
  	*/
  	virtual void SetZByViewRadius(float newRadius);
  
  	/**
  	* Set the near clip distance.
  	*  Note this will cause a Resize() to properly update the clipping planes
  	* 
  	* @param dist The near clip distance. 
  	*/
  	virtual void SetNearClipDist(float dist);
  
  	/**
  	* Set the far clip distance.
  	*  Note this will cause a Resize() to properly update the clipping planes
  	* 
  	* @param dist The far clip distance. 
  	*/
  	virtual void SetFarClipDist(float dist);
  
  	/**
  	 * Set the point towards which the camera should aim. Since Angel is a 
  	 *  predominantly 2D world, be very careful setting this too far off of
  	 *  perpendicular. 
  	 * 
  	 * @param x The X coordinate at which the Camera will aim. 
  	 * @param y The Y coordinate at which the Camera will aim. 
  	 * @param z The Z coordinate at which the Camera will aim. 
  	 */
  	virtual void SetViewCenter(float x, float y, float z);
  	
  	/**
  	 * Get the current look-at target of the camera. 
  	 * 
  	 * @return The point where the Camera is currently looking. 
  	 */
  	const Vector3& GetViewCenter() const;
  	
  	/**
  	 * Used by the SetName function to create a basename for this class. 
  	 *  Overridden from Actor::GetClassName.
  	 * 
  	 * @return The string "Camera"
  	 */
  	virtual const String GetClassName() const { return "Camera"; }
  
  protected:
  	Camera();
  	static Camera *s_Camera;
  
  	void Resize(int w, int h);
  
  private:
  	int _windowWidth;
  	int _windowHeight;
  	double _aperture;
  	Vector3 _camera3DPosition;
  	Vector3 _view;
  	Vector3 _up;
  
  	float _zNearClip;
  	float _zFarClip;
  	
  	Actor* _locked;
  	bool _lockX;
  	bool _lockY;
  	bool _lockRotation;
      
      Interval<Vector3> _3dPositionInterval;
      String _3dPositionIntervalMessage;
  };
  