diff --git a/Engines/FlatRedBallXNA/FlatRedBall/Camera.Common.cs b/Engines/FlatRedBallXNA/FlatRedBall/Camera.Common.cs
deleted file mode 100644
index e381bad77..000000000
--- a/Engines/FlatRedBallXNA/FlatRedBall/Camera.Common.cs
+++ /dev/null
@@ -1,970 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using FlatRedBall.Graphics;
-using FlatRedBall.Math;
-#if FRB_MDX
-using Microsoft.DirectX;
-using System.Drawing;
-#else
-using Microsoft.Xna.Framework;
-
-#endif
-
-namespace FlatRedBall
-{
- // Camera.Common was an effort to make FRB more cross platform before the unification of
- // .NET. Now this isn't needed anymore and we can migrate the .Common things to regular Camera.
- public partial class Camera
- {
-
- #region Fields
-
-
- float mYEdge;
- float mXEdge;
-
- float mTopDestination;
- float mBottomDestination;
- float mLeftDestination;
- float mRightDestination;
-
- internal Rectangle mDestinationRectangle;
-
- float mTopDestinationVelocity;
- float mBottomDestinationVelocity;
- float mLeftDestinationVelocity;
- float mRightDestinationVelocity;
-
-
- float mFieldOfView;
- float mAspectRatio;
-
- bool mDrawsWorld = true;
- bool mDrawsCameraLayer = true;
- bool mDrawsShapes = true;
- #endregion
-
- #region Properties
-
- public static Camera Main
- {
- get
- {
- return SpriteManager.Camera;
- }
- }
-
- #region XML Docs
- ///
- /// Gets and sets the top side of the destination rectangle (where on the window
- /// the camera will display). Measured in pixels. Destination uses an inverted Y (positive points down).
- ///
- #endregion
- public virtual float TopDestination
- {
- get { return mTopDestination; }
- set
- {
- mTopDestination = value;
- mUsesSplitScreenViewport = false;
- UpdateDestinationRectangle();
- }
- }
-
- #region XML Docs
- ///
- /// Gets and sets the bottom side of the destination rectangle (where on the window
- /// the camera will display). Measured in pixels. Destination uses an inverted Y (positive points down).
- ///
- #endregion
- public virtual float BottomDestination
- {
- get { return mBottomDestination; }
- set
- {
- mBottomDestination = value;
- mUsesSplitScreenViewport = false;
- UpdateDestinationRectangle();
- }
- }
-
- #region XML Docs
- ///
- /// Gets and sets the left side of the destination rectangle (where on the window
- /// the camera will display). Measured in pixels.
- ///
- #endregion
- public virtual float LeftDestination
- {
- get { return mLeftDestination; }
- set
- {
- mLeftDestination = value;
- mUsesSplitScreenViewport = false;
- UpdateDestinationRectangle();
- }
- }
-
- #region XML Docs
- ///
- /// Gets and sets the right side of the destination rectangle (where on the window
- /// the camera will display). Measured in pixels.
- ///
- #endregion
- public virtual float RightDestination
- {
- get { return mRightDestination; }
- set
- {
- mRightDestination = value;
- mUsesSplitScreenViewport = false;
- UpdateDestinationRectangle();
- }
- }
-
- #region XML Docs
- ///
- /// Represents the top left justified area the Camera will draw over.
- ///
- ///
- /// This represents the area in pixel coordinates that the camera will display relative
- /// to the top left of the owning Control. If the Control is resized, the camera should modify
- /// its DestinationRectangle to match the new area.
- ///
- ///
- /// Multiple cameras with different DestinationRectangles can be used to display split screen
- /// or picture-in-picture.
- ///
- ///
- #endregion
- public virtual Rectangle DestinationRectangle
- {
- get
- {
- return mDestinationRectangle;
- }
- set
- {
- mUsesSplitScreenViewport = false;
-
- mDestinationRectangle = value;
-
- mTopDestination = mDestinationRectangle.Top;
- mBottomDestination = mDestinationRectangle.Bottom;
- mLeftDestination = mDestinationRectangle.Left;
- mRightDestination = mDestinationRectangle.Right;
-
- FixAspectRatioYConstant();
- }
- }
-
- ///
- /// Returns the absolute X value of the right edge of the visible area for this camera at Z = 0.
- ///
- public float AbsoluteRightXEdge => AbsoluteRightXEdgeAt(0);
-
- ///
- /// Returns the right-most visible X value at a given absolute Z value.
- /// The absoluteZ parameter is ignored if the camera has its Orthogonal = true (is 2D)
- ///
- /// The absolute Z to use for determining the right-edge.
- /// The furthest-right visible X value at the given absolute Z.
- public float AbsoluteRightXEdgeAt(float absoluteZ)
- {
- return Position.X + RelativeXEdgeAt(absoluteZ);
- }
-
- ///
- /// Returns the absolute X value of the left edge of the visible area for this camera at Z = 0.
- ///
- public float AbsoluteLeftXEdge => AbsoluteLeftXEdgeAt(0);
-
- ///
- /// Returns the left-most visible X value at a given absolute Z value.
- /// The absoluteZ parameter is ignored if the camera has its Orthogonal = true (is 2D)
- ///
- /// The absolute Z to use for determing the left-edge.
- /// The furthest-left visible X value at the given absolute Z.
- public float AbsoluteLeftXEdgeAt(float absoluteZ)
- {
- return Position.X - RelativeXEdgeAt(absoluteZ);
- }
-
- ///
- /// Returns the absolute Y value of the top edge of the visible area for this camera at Z = 0.
- ///
- public float AbsoluteTopYEdge => AbsoluteTopYEdgeAt(0);
-
- ///
- /// Returns the top-most visible Y value at a given absolute Z value.
- /// The absoluteZ parameter is ignored if the camera has its Orthogonal = true (is 2D)
- ///
- /// The absolute Z to use for determining the top-edge.
- /// The furthest-top visible Y value at the given absolute Z.
- public float AbsoluteTopYEdgeAt(float absoluteZ)
- {
- return Position.Y + RelativeYEdgeAt(absoluteZ);
- }
-
- ///
- /// Returns the absolute Y value of the bottom edge of the visible area for this camera at Z = 0.
- ///
- public float AbsoluteBottomYEdge => AbsoluteBottomYEdgeAt(0);
-
- ///
- /// Returns the bottom-most visible Y value at a given absolute Z value.
- /// The absoluteZ parameter is ignored if the camera has its Orthogonal = true (is 2D)
- ///
- /// The absolute Z to use for determining the bottom-edge.
- /// The furthest-bottom visible Y value at the given absolute Z.
- public float AbsoluteBottomYEdgeAt(float absoluteZ)
- {
- return Position.Y - RelativeYEdgeAt(absoluteZ);
- }
-
- public bool ClearsDepthBuffer
- {
- get;
- set;
- }
-
- #region XML Docs
- ///
- /// The width/height of the view of the camera
- ///
- ///
- /// This determines the ratio of the width to height of the camera. By default, the aspect ratio is 4/3,
- /// but this should be changed for widescreen monitors or in situations using multiple cameras. For example, if
- /// a game is in split screen with a vertical split, then each camera will show the same height, but half the width.
- /// The aspect ratio should be 2/3.
- ///
- #endregion
- public float AspectRatio
- {
- get { return mAspectRatio; }
- set
- {
- mAspectRatio = value;
- mXEdge = mYEdge * AspectRatio;
- // The user may expect AspectRatio to work when in 2D mode
- if (mOrthogonal)
- {
- mOrthogonalWidth = mOrthogonalHeight * mAspectRatio;
- }
- }
- }
-
-
- ///
- /// Returns whether the camera is using an orthogonal perspective. If true, the camera is 2D.
- ///
- public bool Orthogonal
- {
- get => mOrthogonal;
- set => mOrthogonal = value;
- }
-
-
-
- ///
- /// Whether the camera draws its layers.
- ///
- public bool DrawsCameraLayer
- {
- get { return mDrawsCameraLayer; }
- set { mDrawsCameraLayer = value; }
- }
-
- ///
- /// Whether the Camera draws world objects (objects not on the Camera's Layer). This is true by default.
- /// This is usually set to false for cameras used in render targets which only draw layers.
- ///
- public bool DrawsWorld
- {
- get { return mDrawsWorld; }
- set { mDrawsWorld = value; }
- }
-
- #region XML Docs
- ///
- /// Whether the Camera draws shapes
- ///
- #endregion
- public bool DrawsShapes
- {
- get { return mDrawsShapes; }
- set { mDrawsShapes = value; }
- }
-
- public bool DrawsToScreen
- {
- get;
- set;
- }
-
- #endregion
-
- #region XML Docs
- ///
- /// Sets the aspectRatio to match the width/height of the area that the camera is drawing to.
- ///
- ///
- /// This is usually used in applications with split screen or when on a widescreen display.
- ///
- #endregion
- public void FixAspectRatioYConstant()
- {
- // We may have a 0-height
- // DestinationRectangle in
- // test scenarios.
- if (mDestinationRectangle.Height != 0)
- {
- this.AspectRatio = (float)mDestinationRectangle.Width / (float)mDestinationRectangle.Height;
-
- mOrthogonalWidth = mOrthogonalHeight * mAspectRatio;
- }
- }
-
-
- public void FixAspectRatioXConstant()
- {
- float oldWidth = mOrthogonalWidth;
- float newAspectRatio = mDestinationRectangle.Width / (float)mDestinationRectangle.Height;
- this.FieldOfView *= newAspectRatio / mAspectRatio;
- AspectRatio = newAspectRatio;
-
- mOrthogonalWidth = oldWidth;
- mOrthogonalHeight = mOrthogonalWidth / mAspectRatio;
-
- }
-
- ///
- /// Checks if an Entity is within the Camera's boundaries.
- ///
- /// The entity to check
- /// A buffer zone to account for entity size on boundary check. Defaults to 0
- /// Returns true in case it is inside the camera's boundaries, false otherwise
- public bool IsEntityInView(PositionedObject entity, float buffer = 0)
- {
- return IsEntityInView(entity.Position, buffer);
- }
-
- ///
- /// Checks if an object with Vector3 position is inside the Camera's boundaries.
- ///
- /// The position of the entity to check
- /// A buffer zone to account for entity size on boundary check. Defaults to 0
- /// Returns true in case it is inside the camera's boundaries, false otherwise
- public bool IsEntityInView(Vector3 position, float buffer = 0)
- {
- var z = position.Z;
-
- bool isOnScreen = position.X < Camera.Main.AbsoluteRightXEdgeAt(z) + buffer &&
- position.X > Camera.Main.AbsoluteLeftXEdgeAt(z) - buffer &&
- position.Y < Camera.Main.AbsoluteTopYEdgeAt(z) + buffer &&
- position.Y > Camera.Main.AbsoluteBottomYEdgeAt(z) - buffer;
-
- return isOnScreen;
- }
-
- public bool IsSpriteInView(Sprite sprite)
- {
- return IsSpriteInView(sprite, false);
- }
-
- static float mLongestDimension;
- static float mDistanceFromCamera;
- ///
- /// Returns whether the argument sprite is in view, considering the CameraCullMode. This will always return
- /// true if cull mode is set to None.
- ///
- ///
- /// This method does not do a perfectly precise check of whether the Sprite is on screen or not, as such
- /// a check would require considering the Sprite's rotation. Instead, this uses approximations to avoid
- /// trigonometric functions, and will err on the side of returning true when a Sprite may actually be out
- /// of view.
- ///
- /// The sprite to check in view
- /// Whether the sprite's position is relative to the camera. This value may be true if the
- /// sprite is on a Layer, and the Layer's RelativeToCamera value is true.
- /// Whether the sprite is in view
- ///
- public bool IsSpriteInView(Sprite sprite, bool relativeToCamera)
- {
- switch (CameraCullMode)
- {
-
- case CameraCullMode.UnrotatedDownZ:
- {
- mLongestDimension = (float)(System.Math.Max(sprite.ScaleX, sprite.ScaleY) * 1.42f);
-
-
- if (mOrthogonal)
- {
- if (relativeToCamera)
- {
- if (System.Math.Abs(sprite.X) - mLongestDimension > mOrthogonalWidth)
- {
- return false;
- }
- if (System.Math.Abs(sprite.Y) - mLongestDimension > mOrthogonalHeight)
- {
- return false;
- }
- }
- else
- {
- if (System.Math.Abs(X - sprite.X) - mLongestDimension > mOrthogonalWidth)
- {
- return false;
- }
- if (System.Math.Abs(Y - sprite.Y) - mLongestDimension > mOrthogonalHeight)
- {
- return false;
- }
- }
- }
- else
- {
- // Multiply by 1.5 to increase the range in case the Camera is rotated
- if (relativeToCamera)
- {
- mDistanceFromCamera = (-sprite.Z) / 100.0f;
-
- if (System.Math.Abs(sprite.X) - mLongestDimension > mXEdge * 1.5f * mDistanceFromCamera)
- {
- return false;
- }
- if (System.Math.Abs(sprite.Y) - mLongestDimension > mYEdge * 1.5f * mDistanceFromCamera)
- {
- return false;
- }
- }
- else
- {
- mDistanceFromCamera = (Z - sprite.Z) / 100.0f;
-
- if (System.Math.Abs(X - sprite.X) - mLongestDimension > mXEdge * 1.5f * mDistanceFromCamera)
- {
- return false;
- }
- if (System.Math.Abs(Y - sprite.Y) - mLongestDimension > mYEdge * 1.5f * mDistanceFromCamera)
- {
- return false;
- }
- }
- }
- }
- return true;
- case CameraCullMode.None:
- return true;
- }
- return true;
-
- }
-
- public bool IsTextInView(Text text, bool relativeToCamera)
- {
- if(this.CameraCullMode == Graphics.CameraCullMode.UnrotatedDownZ)
- {
- float cameraLeft;
- float cameraRight;
- float cameraTop;
- float cameraBottom;
-
- if(relativeToCamera)
- {
- cameraLeft = -this.RelativeXEdgeAt(text.Z);
- cameraRight = this.RelativeXEdgeAt(text.Z);
- cameraTop = this.RelativeYEdgeAt(text.Z);
- cameraBottom = -this.RelativeYEdgeAt(text.Z);
-
- }
- else
- {
- cameraLeft = this.AbsoluteLeftXEdgeAt(text.Z);
- cameraRight = this.AbsoluteRightXEdgeAt(text.Z);
- cameraTop = this.AbsoluteTopYEdgeAt(text.Z);
- cameraBottom = this.AbsoluteBottomYEdgeAt(text.Z);
- }
- float textVerticalCenter = text.VerticalCenter;
- float textHorizontalCenter = text.HorizontalCenter;
-
- float longestCenterToEdge
- = (float)(System.Math.Max(text.Width, text.Height) * 1.42f/2.0f);
-
-
- float textLeft = textHorizontalCenter - longestCenterToEdge;
- float textRight = textHorizontalCenter + longestCenterToEdge;
- float textTop = textVerticalCenter + longestCenterToEdge;
- float textBottom = textVerticalCenter - longestCenterToEdge;
-
- return textRight > cameraLeft &&
- textLeft < cameraRight &&
- textBottom < cameraTop &&
- textTop > cameraBottom;
- }
-
-
- return true;
- }
-
- public bool IsPointInView(double x, double y, double absoluteZ)
- {
- if (mOrthogonal)
- {
- return (x > Position.X - mOrthogonalWidth / 2.0f && x < Position.X + mOrthogonalWidth / 2.0f) &&
- y > Position.Y - mOrthogonalHeight / 2.0f && y < Position.Y + mOrthogonalHeight / 2.0f;
- }
- else
- {
-#if FRB_MDX
- double cameraDistance = (absoluteZ - Position.Z) / 100.0;
-#else
- double cameraDistance = (Position.Z - absoluteZ) / 100.0;
-#endif
- if (x > Position.X - mXEdge * cameraDistance && x < Position.X + mXEdge * cameraDistance &&
- y > Position.Y - mYEdge * cameraDistance && y < Position.Y + mYEdge * cameraDistance)
- return true;
- else
- return false;
- }
- }
-
- #region XML Docs
- ///
- /// Determines if the X value is in view, assuming the camera is viewing down the Z axis.
- ///
- ///
- /// Currently, this method assumes viewing down the Z axis.
- ///
- /// The absolute X position of the point.
- /// The absolute Z position of the point.
- ///
- #endregion
- public bool IsXInView(double x, double absoluteZ)
- {
- if (mOrthogonal)
- {
- return (x > Position.X - mOrthogonalWidth / 2.0f && x < Position.X + mOrthogonalWidth / 2.0f);
- }
- else
- {
-#if FRB_MDX
- double cameraDistance = (absoluteZ - Position.Z) / 100.0;
-#else
- double cameraDistance = (Position.Z - absoluteZ) / 100.0;
-#endif
- if (x > Position.X - mXEdge * cameraDistance && x < Position.X + mXEdge * cameraDistance)
- return true;
- else
- return false;
- }
- }
-
- ///
- /// Determines if the Y value is in view, assuming the camera is viewing down the Z axis.
- ///
- ///
- /// Currently, this method assumes viewing down the Z axis.
- ///
- /// The absolute Y position of the point.
- /// The absolute Z position of the point.
- ///
- public bool IsYInView(double y, double absoluteZ)
- {
- if (mOrthogonal)
- {
- return y > Position.Y - mOrthogonalHeight / 2.0f && y < Position.Y + mOrthogonalHeight / 2.0f;
- }
- else
- {
-#if FRB_MDX
- double cameraDistance = (absoluteZ - Position.Z) / 100.0;
-#else
- double cameraDistance = (Position.Z - absoluteZ) / 100.0;
-#endif
- if (y > Position.Y - mYEdge * cameraDistance && y < Position.Y + mYEdge * cameraDistance)
- return true;
- else
- return false;
- }
- }
-
-
- ///
- /// Returns the number of pixels per unit at the given absolute Z value. Assumes
- /// that the Camera is unrotated.
- ///
- ///
- /// If using the PixelsPerUnitAt for a rotated camera, use the overload which
- /// takes a Vector3 argument.
- ///
- /// The absolute Z position.
- /// The number of pixels per world unit (perpendicular to the camera's forward vector).
- public float PixelsPerUnitAt(float absoluteZ)
- {
- // June 7, 2011
- // This used to use
- // width values, but
- // that means aspect ratio
- // can screw with these values
- // which we don't want. Instead
- // we should use height, as that is
- // usually what FRB games use as their
- //// fixed dimension
- //if (mOrthogonal)
- //{
- // return mDestinationRectangle.Width / mOrthogonalWidth;
- //}
- //else
- //{
- // return mDestinationRectangle.Width / (2 * RelativeXEdgeAt(absoluteZ));
- //}
-
- if (mOrthogonal)
- {
- return mDestinationRectangle.Height / mOrthogonalHeight;
- }
- else
- {
- return mDestinationRectangle.Height / (2 * RelativeYEdgeAt(absoluteZ));
- }
-
- }
-
-
- public float PixelsPerUnitAt(ref Vector3 absolutePosition)
- {
-
- return PixelsPerUnitAt(ref absolutePosition, mFieldOfView, mOrthogonal, mOrthogonalHeight);
- }
-
-
- public float PixelsPerUnitAt(ref Vector3 absolutePosition, float fieldOfView, bool orthogonal, float orthogonalHeight)
- {
- if (orthogonal)
- {
- return mDestinationRectangle.Height / orthogonalHeight;
- }
- else
- {
- float distance = Vector3.Dot(
- (absolutePosition - Position), RotationMatrix.Forward);
-
- return mDestinationRectangle.Height /
- (2 * RelativeYEdgeAt(Position.Z + (Math.MathFunctions.ForwardVector3.Z * distance), fieldOfView, mAspectRatio, orthogonal, orthogonalHeight));
- }
- }
-
-
-
- public float RelativeXEdgeAt(float absoluteZ)
- {
- return RelativeXEdgeAt(absoluteZ, mFieldOfView, mAspectRatio, mOrthogonal, mOrthogonalWidth);
- }
-
-
- public float RelativeXEdgeAt(float absoluteZ, float fieldOfView, float aspectRatio, bool orthogonal, float orthogonalWidth)
- {
- if (orthogonal)
- {
- return orthogonalWidth / 2.0f;
- }
- else
- {
- float yEdge = (float)(100 * System.Math.Tan(fieldOfView / 2.0));
- float xEdge = yEdge * aspectRatio;
- return xEdge * (absoluteZ - Position.Z) / 100 * FlatRedBall.Math.MathFunctions.ForwardVector3.Z;
- }
- }
-
-
- public float RelativeYEdgeAt(float absoluteZ)
- {
- return RelativeYEdgeAt(absoluteZ, mFieldOfView, AspectRatio, Orthogonal, OrthogonalHeight);
- }
-
-
- public float RelativeYEdgeAt(float absoluteZ, float fieldOfView, float aspectRatio, bool orthogonal, float orthogonalHeight)
- {
- if (orthogonal)
- {
- // fieldOfView is ignored if it's Orthogonal
- return orthogonalHeight / 2.0f;
- }
- else
- {
- float yEdge = (float)(System.Math.Tan(fieldOfView / 2.0));
-
- return yEdge * (absoluteZ - Position.Z) / FlatRedBall.Math.MathFunctions.ForwardVector3.Z;
- }
- }
-
-
- #region XML Docs
- ///
- /// Sets the camera to Orthogonal, sets the OrthogonalWidth and
- /// OrthogonalHeight to match the argument values, and can move the
- /// so the bottom-left corner of the screen is at the origin.
- ///
- /// Whether the camera should be repositioned
- /// so the bottom left is at the origin.
- /// The desired unit width of the view.
- /// The desired unit height of the view.
- #endregion
- public void UsePixelCoordinates(bool moveCornerToOrigin, int desiredWidth, int desiredHeight)
- {
- this.Orthogonal = true;
- OrthogonalWidth = desiredWidth;
- OrthogonalHeight = desiredHeight;
-
- if (moveCornerToOrigin)
- {
- X = OrthogonalWidth / 2.0f;
- Y = OrthogonalHeight / 2.0f;
- }
- }
-
- ///
- /// Adjusts the camera's Z value so that 1 unit equals 1 pixel at the argument absolute Z value.
- /// Note that objects closer to the camera will appear bigger and objects further will appear smaller.
- /// This function assumes that Orthogonal is set to false.
- ///
- /// The absolute Z value to make pixel perfect.
- public void UsePixelCoordinates3D(float zToMakePixelPerfect)
- {
- double distance = GetZDistanceForPixelPerfect();
- this.Z = -MathFunctions.ForwardVector3.Z * (float)(distance) + zToMakePixelPerfect;
- this.FarClipPlane = System.Math.Max(this.FarClipPlane,
- (float)distance * 2);
- }
-
- public float GetZDistanceForPixelPerfect()
- {
- double sin = System.Math.Sin(FieldOfView / 2.0);
- double cos = System.Math.Cos(FieldOfView / 2.0f);
-
-
- double edgeToEdge = 2 * sin;
- float desiredHeight = this.DestinationRectangle.Height;
-
- double distance = cos * desiredHeight / edgeToEdge;
- return (float)distance;
- }
-
-
- public float WorldXAt(float screenX, float zPosition)
- {
- return WorldXAt(screenX, zPosition, this.Orthogonal, this.OrthogonalWidth);
- }
-
- public float WorldXAt(float screenX, float zPosition, Layer layer)
- {
- if (layer == null || layer.LayerCameraSettings == null)
- {
- return WorldXAt(screenX, zPosition, this.Orthogonal, this.OrthogonalWidth);
- }
- else
- {
- LayerCameraSettings lcs = layer.LayerCameraSettings;
-
- Camera cameraToUse = layer.CameraBelongingTo;
-
- if (cameraToUse == null)
- {
- cameraToUse = this;
- }
-
- // If the orthogonal resolution per destination width/height
- // of the layer matches the Camera's orthogonal per destination, then
- // we can just use the camera. This is the most common case so we'll just
- // use that.
- float destinationLeft = cameraToUse.DestinationRectangle.Left;
- float destinationRight = cameraToUse.DestinationRectangle.Right;
-
-
- float destinationWidth = destinationRight - destinationLeft;
-
- float horizontalPercentage = (screenX - destinationLeft) / (float)destinationWidth;
-
- float orthogonalWidthToUse = cameraToUse.OrthogonalWidth;
-
- var useLayerOrtho = lcs.Orthogonal && !cameraToUse.Orthogonal;
-
- if (useLayerOrtho)
- {
- orthogonalWidthToUse = lcs.OrthogonalWidth;
- }
-
- // used for adjusting the ortho width/height if the Layer is zoomed
- float layerMultiplier = 1;
- float bottomDestination = lcs.BottomDestination;
- float topDestination = lcs.TopDestination;
- if (bottomDestination == -1 || topDestination == -1)
- {
- bottomDestination = cameraToUse.BottomDestination;
- topDestination = cameraToUse.TopDestination;
- }
-
- // Make sure the destinations aren't equal or else we'd divide by 0
- if (lcs.Orthogonal && bottomDestination != topDestination)
- {
- layerMultiplier = lcs.OrthogonalHeight / (float)(bottomDestination - topDestination);
- }
-
- float cameraMultiplier = 1;
- // Make sure the destinations aren't equal or else we'd divide by 0
- if (cameraToUse.Orthogonal && cameraToUse.BottomDestination != cameraToUse.TopDestination)
- {
- cameraMultiplier = cameraToUse.OrthogonalHeight / (float)(cameraToUse.BottomDestination - cameraToUse.TopDestination);
- }
- layerMultiplier /= cameraMultiplier;
-
- if(!useLayerOrtho)
- {
- orthogonalWidthToUse *= layerMultiplier;
- }
-
- // I think we want to use the Camera's orthogonalWidth if it's orthogonal
- //return GetWorldXGivenHorizontalPercentage(zPosition, cameraToUse, lcs.Orthogonal, lcs.OrthogonalWidth, horizontalPercentage);
- return GetWorldXGivenHorizontalPercentage(zPosition, lcs.Orthogonal, orthogonalWidthToUse, horizontalPercentage);
- }
- }
-
- public float WorldXAt(float screenX, float zPosition, bool overridingOrthogonal, float overridingOrthogonalWidth)
- {
- float screenRelativeX = screenX;
- return WorldXAt(zPosition, overridingOrthogonal, overridingOrthogonalWidth, screenRelativeX);
- }
-
- public float WorldXAt(float zPosition, bool overridingOrthogonal, float overridingOrthogonalWidth, float screenX)
- {
-
- float horizontalPercentage = (screenX - this.DestinationRectangle.Left) / (float)this.DestinationRectangle.Width;
-
- return GetWorldXGivenHorizontalPercentage(zPosition, overridingOrthogonal, overridingOrthogonalWidth, horizontalPercentage);
- }
-
- private float GetWorldXGivenHorizontalPercentage(float zPosition, bool overridingOrthogonal, float overridingOrthogonalWidth, float horizontalPercentage)
- {
- if (!overridingOrthogonal)
- {
- float absoluteLeft = this.AbsoluteLeftXEdgeAt(zPosition);
- float width = this.RelativeXEdgeAt(zPosition) * 2;
- return absoluteLeft + width * horizontalPercentage;
- }
- else
- {
- float xDistanceFromEdge = horizontalPercentage * overridingOrthogonalWidth;
- return (this.X + -overridingOrthogonalWidth / 2.0f + xDistanceFromEdge);
- }
- }
-
-
- public float WorldYAt(float screenY, float zPosition)
- {
- return WorldYAt(screenY, zPosition, this.Orthogonal, this.OrthogonalHeight);
- }
-
- public float WorldYAt(float screenY, float zPosition, Layer layer)
- {
- if (layer == null || layer.LayerCameraSettings == null)
- {
- return WorldYAt(screenY, zPosition, this.Orthogonal, this.OrthogonalHeight);
- }
- else
- {
- LayerCameraSettings lcs = layer.LayerCameraSettings;
-
- Camera cameraToUse = layer.CameraBelongingTo;
-
- if (cameraToUse == null)
- {
- cameraToUse = this;
- }
-
-
- // If the orthogonal resolution per destination width/height
- // of the layer matches the Camera's orthogonal per destination, then
- // we can just use the camera. This is the most common case so we'll just
- // use that.
- //return WorldYAt(zPosition, cameraToUse, lcs.Orthogonal, lcs.OrthogonalHeight);
- // If we have a 2D layer ona 3D camera, then we shouldn't use the Camera's orthogonal values
- float orthogonalHeightToUse = cameraToUse.OrthogonalHeight;
-
- // multiplier is used if the orghogonal height of the layer doesn't match the orthogonal height of the
- // camera. But if we're going to pass the ortho height of the layer, then the multiplier should be 1
-
- var usedLayerOrtho = lcs.Orthogonal && !cameraToUse.Orthogonal;
-
- if (usedLayerOrtho)
- {
- orthogonalHeightToUse = lcs.OrthogonalHeight;
- }
-
- float layerMultiplier = 1;
- float bottomDestination = lcs.BottomDestination;
- float topDestination = lcs.TopDestination;
- if (bottomDestination == -1 || topDestination == -1)
- {
- bottomDestination = cameraToUse.BottomDestination;
- topDestination = cameraToUse.TopDestination;
- }
-
- if (lcs.Orthogonal && bottomDestination != topDestination)
- {
- layerMultiplier = lcs.OrthogonalHeight / (float)(bottomDestination - topDestination);
- }
-
- float cameraMultiplier = 1;
- if (cameraToUse.Orthogonal && cameraToUse.BottomDestination != cameraToUse.TopDestination)
- {
- cameraMultiplier = cameraToUse.OrthogonalHeight / (float)(cameraToUse.BottomDestination - cameraToUse.TopDestination);
- }
- layerMultiplier /= cameraMultiplier;
-
- if(!usedLayerOrtho)
- {
- orthogonalHeightToUse *= layerMultiplier;
- }
-
- return WorldYAt(screenY, zPosition, lcs.Orthogonal, orthogonalHeightToUse);
- }
- }
-
- public float WorldYAt(float screenY, float zPosition, bool overridingOrthogonal, float overridingOrthogonalHeight)
- {
- float screenRelativeY = screenY;
-
- return WorldYAt(zPosition, overridingOrthogonal, overridingOrthogonalHeight, screenRelativeY);
- }
-
- public float WorldYAt(float zPosition, bool orthogonal, float orthogonalHeight, float screenY)
- {
- float verticalPercentage = (screenY - this.DestinationRectangle.Top) / (float)this.DestinationRectangle.Height;
-
- if (!orthogonal)
- {
- float absoluteTop = this.AbsoluteTopYEdgeAt(zPosition);
- float height = this.RelativeYEdgeAt(zPosition) * 2;
- return absoluteTop - height * verticalPercentage;
- }
- else
- {
- float yDistanceFromEdge = verticalPercentage * orthogonalHeight;
- return (this.Y + orthogonalHeight / 2.0f - yDistanceFromEdge);
- }
- }
-
-
-
-
-
-
- }
-
-
-}
diff --git a/Engines/FlatRedBallXNA/FlatRedBall/Camera.cs b/Engines/FlatRedBallXNA/FlatRedBall/Camera.cs
index 1af4d6894..11d6ae704 100644
--- a/Engines/FlatRedBallXNA/FlatRedBall/Camera.cs
+++ b/Engines/FlatRedBallXNA/FlatRedBall/Camera.cs
@@ -147,13 +147,34 @@ public enum SplitScreenViewport
string mContentManager;
- #region XML Docs
///
/// Whether or not lighting is enabled for this camera
///
- #endregion
internal bool mLightingEnabled = false;
-
+
+ float mYEdge;
+ float mXEdge;
+
+ float mTopDestination;
+ float mBottomDestination;
+ float mLeftDestination;
+ float mRightDestination;
+
+ internal Rectangle mDestinationRectangle;
+
+ float mTopDestinationVelocity;
+ float mBottomDestinationVelocity;
+ float mLeftDestinationVelocity;
+ float mRightDestinationVelocity;
+
+
+ float mFieldOfView;
+ float mAspectRatio;
+
+ bool mDrawsWorld = true;
+ bool mDrawsCameraLayer = true;
+ bool mDrawsShapes = true;
+
#endregion
#region Properties
@@ -235,7 +256,6 @@ public virtual float FieldOfView
}
}
- #region XML Docs
///
/// A Camera-specific layer. Objects on this layer will not appear
/// in any other cameras.
@@ -243,7 +263,6 @@ public virtual float FieldOfView
///
/// This instance is automatically created when the Camera is instantiated.
///
- #endregion
public Layer Layer
{
get { return mLayers[0]; }
@@ -339,6 +358,126 @@ public float RightDestinationVelocity
set { mRightDestinationVelocity = value; }
}
+ ///
+ /// The absolute X value of the right edge of the visible area for this camera at Z = 0.
+ ///
+ public float AbsoluteRightXEdge
+ {
+ get => AbsoluteRightXEdgeAt(0);
+ set
+ {
+ if (this.Orthogonal)
+ {
+ X = value - OrthogonalWidth / 2.0f;
+ }
+ else
+ {
+ throw new NotImplementedException("Setting the AbsoluteRightXEdge is not supported for perspective cameras.")
+ }
+ }
+ }
+
+
+ ///
+ /// Returns the right-most visible X value at a given absolute Z value.
+ /// The absoluteZ parameter is ignored if the camera has its Orthogonal = true (is 2D)
+ ///
+ /// The absolute Z to use for determining the right-edge.
+ /// The furthest-right visible X value at the given absolute Z.
+ public float AbsoluteRightXEdgeAt(float absoluteZ)
+ {
+ return Position.X + RelativeXEdgeAt(absoluteZ);
+ }
+
+ ///
+ /// Returns the absolute X value of the left edge of the visible area for this camera at Z = 0.
+ ///
+ public float AbsoluteLeftXEdge
+ {
+ get => AbsoluteLeftXEdgeAt(0);
+ set
+ {
+ if (this.Orthogonal)
+ {
+ X = value + OrthogonalWidth / 2.0f;
+ }
+ else
+ {
+ throw new NotImplementedException("Setting the AbsoluteLeftXEdge is not supported for perspective cameras.");
+ }
+ }
+ }
+
+ ///
+ /// Returns the left-most visible X value at a given absolute Z value.
+ /// The absoluteZ parameter is ignored if the camera has its Orthogonal = true (is 2D)
+ ///
+ /// The absolute Z to use for determing the left-edge.
+ /// The furthest-left visible X value at the given absolute Z.
+ public float AbsoluteLeftXEdgeAt(float absoluteZ)
+ {
+ return Position.X - RelativeXEdgeAt(absoluteZ);
+ }
+
+ ///
+ /// Returns the absolute Y value of the top edge of the visible area for this camera at Z = 0.
+ ///
+ public float AbsoluteTopYEdge
+ {
+ get => AbsoluteTopYEdgeAt(0);
+ set
+ {
+ if (this.Orthogonal)
+ {
+ Y = value - OrthogonalHeight / 2.0f;
+ }
+ else
+ {
+ throw new NotImplementedException("Setting the AbsoluteTopYEdge is not supported for perspective cameras.");
+ }
+ }
+ }
+
+ ///
+ /// Returns the top-most visible Y value at a given absolute Z value.
+ /// The absoluteZ parameter is ignored if the camera has its Orthogonal = true (is 2D)
+ ///
+ /// The absolute Z to use for determining the top-edge.
+ /// The furthest-top visible Y value at the given absolute Z.
+ public float AbsoluteTopYEdgeAt(float absoluteZ)
+ {
+ return Position.Y + RelativeYEdgeAt(absoluteZ);
+ }
+
+ ///
+ /// Returns the absolute Y value of the bottom edge of the visible area for this camera at Z = 0.
+ ///
+ public float AbsoluteBottomYEdge
+ {
+ get => AbsoluteBottomYEdgeAt(0);
+ set
+ {
+ if (this.Orthogonal)
+ {
+ Y = value + OrthogonalHeight / 2.0f;
+ }
+ else
+ {
+ throw new NotImplementedException("Setting the AbsoluteBottomYEdge is not supported for perspective cameras.");
+ }
+ }
+ }
+
+ ///
+ /// Returns the bottom-most visible Y value at a given absolute Z value.
+ /// The absoluteZ parameter is ignored if the camera has its Orthogonal = true (is 2D)
+ ///
+ /// The absolute Z to use for determining the bottom-edge.
+ /// The furthest-bottom visible Y value at the given absolute Z.
+ public float AbsoluteBottomYEdgeAt(float absoluteZ)
+ {
+ return Position.Y - RelativeYEdgeAt(absoluteZ);
+ }
///
/// The number of horizontal units shown by the camera when the camera has Orthogonal = true
@@ -382,6 +521,186 @@ public float OrthogonalHeight
}
}
+ public static Camera Main
+ {
+ get
+ {
+ return SpriteManager.Camera;
+ }
+ }
+
+ ///
+ /// Gets and sets the top side of the destination rectangle (where on the window
+ /// the camera will display). Measured in pixels. Destination uses an inverted Y (positive points down).
+ ///
+ public virtual float TopDestination
+ {
+ get { return mTopDestination; }
+ set
+ {
+ mTopDestination = value;
+ mUsesSplitScreenViewport = false;
+ UpdateDestinationRectangle();
+ }
+ }
+
+ ///
+ /// Gets and sets the bottom side of the destination rectangle (where on the window
+ /// the camera will display). Measured in pixels. Destination uses an inverted Y (positive points down).
+ ///
+ public virtual float BottomDestination
+ {
+ get { return mBottomDestination; }
+ set
+ {
+ mBottomDestination = value;
+ mUsesSplitScreenViewport = false;
+ UpdateDestinationRectangle();
+ }
+ }
+
+ ///
+ /// Gets and sets the left side of the destination rectangle (where on the window
+ /// the camera will display). Measured in pixels.
+ ///
+ public virtual float LeftDestination
+ {
+ get { return mLeftDestination; }
+ set
+ {
+ mLeftDestination = value;
+ mUsesSplitScreenViewport = false;
+ UpdateDestinationRectangle();
+ }
+ }
+
+ ///
+ /// Gets and sets the right side of the destination rectangle (where on the window
+ /// the camera will display). Measured in pixels.
+ ///
+ public virtual float RightDestination
+ {
+ get { return mRightDestination; }
+ set
+ {
+ mRightDestination = value;
+ mUsesSplitScreenViewport = false;
+ UpdateDestinationRectangle();
+ }
+ }
+
+ ///
+ /// Represents the top left justified area the Camera will draw over.
+ ///
+ ///
+ /// This represents the area in pixel coordinates that the camera will display relative
+ /// to the top left of the owning Control. If the Control is resized, the camera should modify
+ /// its DestinationRectangle to match the new area.
+ ///
+ ///
+ /// Multiple cameras with different DestinationRectangles can be used to display split screen
+ /// or picture-in-picture.
+ ///
+ ///
+ public virtual Rectangle DestinationRectangle
+ {
+ get
+ {
+ return mDestinationRectangle;
+ }
+ set
+ {
+ mUsesSplitScreenViewport = false;
+
+ mDestinationRectangle = value;
+
+ mTopDestination = mDestinationRectangle.Top;
+ mBottomDestination = mDestinationRectangle.Bottom;
+ mLeftDestination = mDestinationRectangle.Left;
+ mRightDestination = mDestinationRectangle.Right;
+
+ FixAspectRatioYConstant();
+ }
+ }
+
+ public bool ClearsDepthBuffer
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// The width/height of the view of the camera
+ ///
+ ///
+ /// This determines the ratio of the width to height of the camera. By default, the aspect ratio is 4/3,
+ /// but this should be changed for widescreen monitors or in situations using multiple cameras. For example, if
+ /// a game is in split screen with a vertical split, then each camera will show the same height, but half the width.
+ /// The aspect ratio should be 2/3.
+ ///
+ public float AspectRatio
+ {
+ get { return mAspectRatio; }
+ set
+ {
+ mAspectRatio = value;
+ mXEdge = mYEdge * AspectRatio;
+ // The user may expect AspectRatio to work when in 2D mode
+ if (mOrthogonal)
+ {
+ mOrthogonalWidth = mOrthogonalHeight * mAspectRatio;
+ }
+ }
+ }
+
+
+ ///
+ /// Returns whether the camera is using an orthogonal perspective. If true, the camera is a "2D" camera.
+ ///
+ public bool Orthogonal
+ {
+ get => mOrthogonal;
+ set => mOrthogonal = value;
+ }
+
+
+ ///
+ /// Whether the camera draws its layers.
+ ///
+ public bool DrawsCameraLayer
+ {
+ get { return mDrawsCameraLayer; }
+ set { mDrawsCameraLayer = value; }
+ }
+
+ ///
+ /// Whether the Camera draws world objects (objects not on the Camera's Layer). This is true by default.
+ /// This is usually set to false for cameras used in render targets which only draw layers.
+ ///
+ public bool DrawsWorld
+ {
+ get { return mDrawsWorld; }
+ set { mDrawsWorld = value; }
+ }
+
+ ///
+ /// Whether the Camera draws shapes
+ ///
+ public bool DrawsShapes
+ {
+ get { return mDrawsShapes; }
+ set { mDrawsShapes = value; }
+ }
+
+ ///
+ /// Whether this camera draws its contents to the screen. By default this is true.
+ ///
+ public bool DrawsToScreen
+ {
+ get;
+ set;
+ }
+
#endregion
public bool ShiftsHalfUnitForRendering
@@ -491,7 +810,7 @@ public Camera(string contentManagerName, int width, int height)
#endregion
- #region Public Methods
+ #region Methods
public Layer AddLayer()
{
@@ -1407,6 +1726,7 @@ public void SetSplitScreenViewport(SplitScreenViewport? viewport)
}
}
+ #endregion
#region Internal Methods
@@ -1538,7 +1858,648 @@ private void UpdateDestinationRectangle()
#endregion
- #endregion
+
+
+ ///
+ /// Sets the aspectRatio to match the width/height of the area that the camera is drawing to.
+ ///
+ ///
+ /// This is usually used in applications with split screen or when on a widescreen display.
+ ///
+ public void FixAspectRatioYConstant()
+ {
+ // We may have a 0-height
+ // DestinationRectangle in
+ // test scenarios.
+ if (mDestinationRectangle.Height != 0)
+ {
+ this.AspectRatio = (float)mDestinationRectangle.Width / (float)mDestinationRectangle.Height;
+
+ mOrthogonalWidth = mOrthogonalHeight * mAspectRatio;
+ }
+ }
+
+ public void FixAspectRatioXConstant()
+ {
+ float oldWidth = mOrthogonalWidth;
+ float newAspectRatio = mDestinationRectangle.Width / (float)mDestinationRectangle.Height;
+ this.FieldOfView *= newAspectRatio / mAspectRatio;
+ AspectRatio = newAspectRatio;
+
+ mOrthogonalWidth = oldWidth;
+ mOrthogonalHeight = mOrthogonalWidth / mAspectRatio;
+
+ }
+
+ ///
+ /// Checks if an Entity is within the Camera's boundaries.
+ ///
+ /// The entity to check
+ /// A buffer zone to account for entity size on boundary check. Defaults to 0
+ /// Returns true in case it is inside the camera's boundaries, false otherwise
+ public bool IsEntityInView(PositionedObject entity, float buffer = 0)
+ {
+ return IsEntityInView(entity.Position, buffer);
+ }
+
+ ///
+ /// Checks if an object with Vector3 position is inside the Camera's boundaries.
+ ///
+ /// The position of the entity to check
+ /// A buffer zone to account for entity size on boundary check. Defaults to 0
+ /// Returns true in case it is inside the camera's boundaries, false otherwise
+ public bool IsEntityInView(Vector3 position, float buffer = 0)
+ {
+ var z = position.Z;
+
+ bool isOnScreen = position.X < Camera.Main.AbsoluteRightXEdgeAt(z) + buffer &&
+ position.X > Camera.Main.AbsoluteLeftXEdgeAt(z) - buffer &&
+ position.Y < Camera.Main.AbsoluteTopYEdgeAt(z) + buffer &&
+ position.Y > Camera.Main.AbsoluteBottomYEdgeAt(z) - buffer;
+
+ return isOnScreen;
+ }
+
+ public bool IsSpriteInView(Sprite sprite)
+ {
+ return IsSpriteInView(sprite, false);
+ }
+
+ static float mLongestDimension;
+ static float mDistanceFromCamera;
+ ///
+ /// Returns whether the argument sprite is in view, considering the CameraCullMode. This will always return
+ /// true if cull mode is set to None.
+ ///
+ ///
+ /// This method does not do a perfectly precise check of whether the Sprite is on screen or not, as such
+ /// a check would require considering the Sprite's rotation. Instead, this uses approximations to avoid
+ /// trigonometric functions, and will err on the side of returning true when a Sprite may actually be out
+ /// of view.
+ ///
+ /// The sprite to check in view
+ /// Whether the sprite's position is relative to the camera. This value may be true if the
+ /// sprite is on a Layer, and the Layer's RelativeToCamera value is true.
+ /// Whether the sprite is in view
+ ///
+ public bool IsSpriteInView(Sprite sprite, bool relativeToCamera)
+ {
+ switch (CameraCullMode)
+ {
+
+ case CameraCullMode.UnrotatedDownZ:
+ {
+ mLongestDimension = (float)(System.Math.Max(sprite.ScaleX, sprite.ScaleY) * 1.42f);
+
+
+ if (mOrthogonal)
+ {
+ if (relativeToCamera)
+ {
+ if (System.Math.Abs(sprite.X) - mLongestDimension > mOrthogonalWidth)
+ {
+ return false;
+ }
+ if (System.Math.Abs(sprite.Y) - mLongestDimension > mOrthogonalHeight)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (System.Math.Abs(X - sprite.X) - mLongestDimension > mOrthogonalWidth)
+ {
+ return false;
+ }
+ if (System.Math.Abs(Y - sprite.Y) - mLongestDimension > mOrthogonalHeight)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // Multiply by 1.5 to increase the range in case the Camera is rotated
+ if (relativeToCamera)
+ {
+ mDistanceFromCamera = (-sprite.Z) / 100.0f;
+
+ if (System.Math.Abs(sprite.X) - mLongestDimension > mXEdge * 1.5f * mDistanceFromCamera)
+ {
+ return false;
+ }
+ if (System.Math.Abs(sprite.Y) - mLongestDimension > mYEdge * 1.5f * mDistanceFromCamera)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ mDistanceFromCamera = (Z - sprite.Z) / 100.0f;
+
+ if (System.Math.Abs(X - sprite.X) - mLongestDimension > mXEdge * 1.5f * mDistanceFromCamera)
+ {
+ return false;
+ }
+ if (System.Math.Abs(Y - sprite.Y) - mLongestDimension > mYEdge * 1.5f * mDistanceFromCamera)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ case CameraCullMode.None:
+ return true;
+ }
+ return true;
+
+ }
+
+ public bool IsTextInView(Text text, bool relativeToCamera)
+ {
+ if (this.CameraCullMode == Graphics.CameraCullMode.UnrotatedDownZ)
+ {
+ float cameraLeft;
+ float cameraRight;
+ float cameraTop;
+ float cameraBottom;
+
+ if (relativeToCamera)
+ {
+ cameraLeft = -this.RelativeXEdgeAt(text.Z);
+ cameraRight = this.RelativeXEdgeAt(text.Z);
+ cameraTop = this.RelativeYEdgeAt(text.Z);
+ cameraBottom = -this.RelativeYEdgeAt(text.Z);
+
+ }
+ else
+ {
+ cameraLeft = this.AbsoluteLeftXEdgeAt(text.Z);
+ cameraRight = this.AbsoluteRightXEdgeAt(text.Z);
+ cameraTop = this.AbsoluteTopYEdgeAt(text.Z);
+ cameraBottom = this.AbsoluteBottomYEdgeAt(text.Z);
+ }
+ float textVerticalCenter = text.VerticalCenter;
+ float textHorizontalCenter = text.HorizontalCenter;
+
+ float longestCenterToEdge
+ = (float)(System.Math.Max(text.Width, text.Height) * 1.42f / 2.0f);
+
+
+ float textLeft = textHorizontalCenter - longestCenterToEdge;
+ float textRight = textHorizontalCenter + longestCenterToEdge;
+ float textTop = textVerticalCenter + longestCenterToEdge;
+ float textBottom = textVerticalCenter - longestCenterToEdge;
+
+ return textRight > cameraLeft &&
+ textLeft < cameraRight &&
+ textBottom < cameraTop &&
+ textTop > cameraBottom;
+ }
+
+
+ return true;
+ }
+
+ public bool IsPointInView(double x, double y, double absoluteZ)
+ {
+ if (mOrthogonal)
+ {
+ return (x > Position.X - mOrthogonalWidth / 2.0f && x < Position.X + mOrthogonalWidth / 2.0f) &&
+ y > Position.Y - mOrthogonalHeight / 2.0f && y < Position.Y + mOrthogonalHeight / 2.0f;
+ }
+ else
+ {
+#if FRB_MDX
+ double cameraDistance = (absoluteZ - Position.Z) / 100.0;
+#else
+ double cameraDistance = (Position.Z - absoluteZ) / 100.0;
+#endif
+ if (x > Position.X - mXEdge * cameraDistance && x < Position.X + mXEdge * cameraDistance &&
+ y > Position.Y - mYEdge * cameraDistance && y < Position.Y + mYEdge * cameraDistance)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ ///
+ /// Determines if the X value is in view, assuming the camera is viewing down the Z axis.
+ ///
+ ///
+ /// Currently, this method assumes viewing down the Z axis.
+ ///
+ /// The absolute X position of the point.
+ /// The absolute Z position of the point.
+ ///
+ public bool IsXInView(double x, double absoluteZ)
+ {
+ if (mOrthogonal)
+ {
+ return (x > Position.X - mOrthogonalWidth / 2.0f && x < Position.X + mOrthogonalWidth / 2.0f);
+ }
+ else
+ {
+#if FRB_MDX
+ double cameraDistance = (absoluteZ - Position.Z) / 100.0;
+#else
+ double cameraDistance = (Position.Z - absoluteZ) / 100.0;
+#endif
+ if (x > Position.X - mXEdge * cameraDistance && x < Position.X + mXEdge * cameraDistance)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ ///
+ /// Determines if the Y value is in view, assuming the camera is viewing down the Z axis.
+ ///
+ ///
+ /// Currently, this method assumes viewing down the Z axis.
+ ///
+ /// The absolute Y position of the point.
+ /// The absolute Z position of the point.
+ ///
+ public bool IsYInView(double y, double absoluteZ)
+ {
+ if (mOrthogonal)
+ {
+ return y > Position.Y - mOrthogonalHeight / 2.0f && y < Position.Y + mOrthogonalHeight / 2.0f;
+ }
+ else
+ {
+#if FRB_MDX
+ double cameraDistance = (absoluteZ - Position.Z) / 100.0;
+#else
+ double cameraDistance = (Position.Z - absoluteZ) / 100.0;
+#endif
+ if (y > Position.Y - mYEdge * cameraDistance && y < Position.Y + mYEdge * cameraDistance)
+ return true;
+ else
+ return false;
+ }
+ }
+
+
+ ///
+ /// Returns the number of pixels per unit at the given absolute Z value. Assumes
+ /// that the Camera is unrotated.
+ ///
+ ///
+ /// If using the PixelsPerUnitAt for a rotated camera, use the overload which
+ /// takes a Vector3 argument.
+ ///
+ /// The absolute Z position.
+ /// The number of pixels per world unit (perpendicular to the camera's forward vector).
+ public float PixelsPerUnitAt(float absoluteZ)
+ {
+ // June 7, 2011
+ // This used to use
+ // width values, but
+ // that means aspect ratio
+ // can screw with these values
+ // which we don't want. Instead
+ // we should use height, as that is
+ // usually what FRB games use as their
+ //// fixed dimension
+ //if (mOrthogonal)
+ //{
+ // return mDestinationRectangle.Width / mOrthogonalWidth;
+ //}
+ //else
+ //{
+ // return mDestinationRectangle.Width / (2 * RelativeXEdgeAt(absoluteZ));
+ //}
+
+ if (mOrthogonal)
+ {
+ return mDestinationRectangle.Height / mOrthogonalHeight;
+ }
+ else
+ {
+ return mDestinationRectangle.Height / (2 * RelativeYEdgeAt(absoluteZ));
+ }
+
+ }
+
+ public float PixelsPerUnitAt(ref Vector3 absolutePosition)
+ {
+
+ return PixelsPerUnitAt(ref absolutePosition, mFieldOfView, mOrthogonal, mOrthogonalHeight);
+ }
+
+ public float PixelsPerUnitAt(ref Vector3 absolutePosition, float fieldOfView, bool orthogonal, float orthogonalHeight)
+ {
+ if (orthogonal)
+ {
+ return mDestinationRectangle.Height / orthogonalHeight;
+ }
+ else
+ {
+ float distance = Vector3.Dot(
+ (absolutePosition - Position), RotationMatrix.Forward);
+
+ return mDestinationRectangle.Height /
+ (2 * RelativeYEdgeAt(Position.Z + (Math.MathFunctions.ForwardVector3.Z * distance), fieldOfView, mAspectRatio, orthogonal, orthogonalHeight));
+ }
+ }
+
+ public float RelativeXEdgeAt(float absoluteZ)
+ {
+ return RelativeXEdgeAt(absoluteZ, mFieldOfView, mAspectRatio, mOrthogonal, mOrthogonalWidth);
+ }
+
+ public float RelativeXEdgeAt(float absoluteZ, float fieldOfView, float aspectRatio, bool orthogonal, float orthogonalWidth)
+ {
+ if (orthogonal)
+ {
+ return orthogonalWidth / 2.0f;
+ }
+ else
+ {
+ float yEdge = (float)(100 * System.Math.Tan(fieldOfView / 2.0));
+ float xEdge = yEdge * aspectRatio;
+ return xEdge * (absoluteZ - Position.Z) / 100 * FlatRedBall.Math.MathFunctions.ForwardVector3.Z;
+ }
+ }
+
+ public float RelativeYEdgeAt(float absoluteZ)
+ {
+ return RelativeYEdgeAt(absoluteZ, mFieldOfView, AspectRatio, Orthogonal, OrthogonalHeight);
+ }
+
+ public float RelativeYEdgeAt(float absoluteZ, float fieldOfView, float aspectRatio, bool orthogonal, float orthogonalHeight)
+ {
+ if (orthogonal)
+ {
+ // fieldOfView is ignored if it's Orthogonal
+ return orthogonalHeight / 2.0f;
+ }
+ else
+ {
+ float yEdge = (float)(System.Math.Tan(fieldOfView / 2.0));
+
+ return yEdge * (absoluteZ - Position.Z) / FlatRedBall.Math.MathFunctions.ForwardVector3.Z;
+ }
+ }
+
+
+ ///
+ /// Sets the camera to Orthogonal, sets the OrthogonalWidth and
+ /// OrthogonalHeight to match the argument values, and can move the
+ /// so the bottom-left corner of the screen is at the origin.
+ ///
+ /// Whether the camera should be repositioned
+ /// so the bottom left is at the origin.
+ /// The desired unit width of the view.
+ /// The desired unit height of the view.
+ public void UsePixelCoordinates(bool moveCornerToOrigin, int desiredWidth, int desiredHeight)
+ {
+ this.Orthogonal = true;
+ OrthogonalWidth = desiredWidth;
+ OrthogonalHeight = desiredHeight;
+
+ if (moveCornerToOrigin)
+ {
+ X = OrthogonalWidth / 2.0f;
+ Y = OrthogonalHeight / 2.0f;
+ }
+ }
+
+ ///
+ /// Adjusts the camera's Z value so that 1 unit equals 1 pixel at the argument absolute Z value.
+ /// Note that objects closer to the camera will appear bigger and objects further will appear smaller.
+ /// This function assumes that Orthogonal is set to false.
+ ///
+ /// The absolute Z value to make pixel perfect.
+ public void UsePixelCoordinates3D(float zToMakePixelPerfect)
+ {
+ double distance = GetZDistanceForPixelPerfect();
+ this.Z = -MathFunctions.ForwardVector3.Z * (float)(distance) + zToMakePixelPerfect;
+ this.FarClipPlane = System.Math.Max(this.FarClipPlane,
+ (float)distance * 2);
+ }
+
+ public float GetZDistanceForPixelPerfect()
+ {
+ double sin = System.Math.Sin(FieldOfView / 2.0);
+ double cos = System.Math.Cos(FieldOfView / 2.0f);
+
+
+ double edgeToEdge = 2 * sin;
+ float desiredHeight = this.DestinationRectangle.Height;
+
+ double distance = cos * desiredHeight / edgeToEdge;
+ return (float)distance;
+ }
+
+
+ public float WorldXAt(float screenX, float zPosition)
+ {
+ return WorldXAt(screenX, zPosition, this.Orthogonal, this.OrthogonalWidth);
+ }
+
+ public float WorldXAt(float screenX, float zPosition, Layer layer)
+ {
+ if (layer == null || layer.LayerCameraSettings == null)
+ {
+ return WorldXAt(screenX, zPosition, this.Orthogonal, this.OrthogonalWidth);
+ }
+ else
+ {
+ LayerCameraSettings lcs = layer.LayerCameraSettings;
+
+ Camera cameraToUse = layer.CameraBelongingTo;
+
+ if (cameraToUse == null)
+ {
+ cameraToUse = this;
+ }
+
+ // If the orthogonal resolution per destination width/height
+ // of the layer matches the Camera's orthogonal per destination, then
+ // we can just use the camera. This is the most common case so we'll just
+ // use that.
+ float destinationLeft = cameraToUse.DestinationRectangle.Left;
+ float destinationRight = cameraToUse.DestinationRectangle.Right;
+
+
+ float destinationWidth = destinationRight - destinationLeft;
+
+ float horizontalPercentage = (screenX - destinationLeft) / (float)destinationWidth;
+
+ float orthogonalWidthToUse = cameraToUse.OrthogonalWidth;
+
+ var useLayerOrtho = lcs.Orthogonal && !cameraToUse.Orthogonal;
+
+ if (useLayerOrtho)
+ {
+ orthogonalWidthToUse = lcs.OrthogonalWidth;
+ }
+
+ // used for adjusting the ortho width/height if the Layer is zoomed
+ float layerMultiplier = 1;
+ float bottomDestination = lcs.BottomDestination;
+ float topDestination = lcs.TopDestination;
+ if (bottomDestination == -1 || topDestination == -1)
+ {
+ bottomDestination = cameraToUse.BottomDestination;
+ topDestination = cameraToUse.TopDestination;
+ }
+
+ // Make sure the destinations aren't equal or else we'd divide by 0
+ if (lcs.Orthogonal && bottomDestination != topDestination)
+ {
+ layerMultiplier = lcs.OrthogonalHeight / (float)(bottomDestination - topDestination);
+ }
+
+ float cameraMultiplier = 1;
+ // Make sure the destinations aren't equal or else we'd divide by 0
+ if (cameraToUse.Orthogonal && cameraToUse.BottomDestination != cameraToUse.TopDestination)
+ {
+ cameraMultiplier = cameraToUse.OrthogonalHeight / (float)(cameraToUse.BottomDestination - cameraToUse.TopDestination);
+ }
+ layerMultiplier /= cameraMultiplier;
+
+ if (!useLayerOrtho)
+ {
+ orthogonalWidthToUse *= layerMultiplier;
+ }
+
+ // I think we want to use the Camera's orthogonalWidth if it's orthogonal
+ //return GetWorldXGivenHorizontalPercentage(zPosition, cameraToUse, lcs.Orthogonal, lcs.OrthogonalWidth, horizontalPercentage);
+ return GetWorldXGivenHorizontalPercentage(zPosition, lcs.Orthogonal, orthogonalWidthToUse, horizontalPercentage);
+ }
+ }
+
+ public float WorldXAt(float screenX, float zPosition, bool overridingOrthogonal, float overridingOrthogonalWidth)
+ {
+ float screenRelativeX = screenX;
+ return WorldXAt(zPosition, overridingOrthogonal, overridingOrthogonalWidth, screenRelativeX);
+ }
+
+ public float WorldXAt(float zPosition, bool overridingOrthogonal, float overridingOrthogonalWidth, float screenX)
+ {
+
+ float horizontalPercentage = (screenX - this.DestinationRectangle.Left) / (float)this.DestinationRectangle.Width;
+
+ return GetWorldXGivenHorizontalPercentage(zPosition, overridingOrthogonal, overridingOrthogonalWidth, horizontalPercentage);
+ }
+
+ private float GetWorldXGivenHorizontalPercentage(float zPosition, bool overridingOrthogonal, float overridingOrthogonalWidth, float horizontalPercentage)
+ {
+ if (!overridingOrthogonal)
+ {
+ float absoluteLeft = this.AbsoluteLeftXEdgeAt(zPosition);
+ float width = this.RelativeXEdgeAt(zPosition) * 2;
+ return absoluteLeft + width * horizontalPercentage;
+ }
+ else
+ {
+ float xDistanceFromEdge = horizontalPercentage * overridingOrthogonalWidth;
+ return (this.X + -overridingOrthogonalWidth / 2.0f + xDistanceFromEdge);
+ }
+ }
+
+
+ public float WorldYAt(float screenY, float zPosition)
+ {
+ return WorldYAt(screenY, zPosition, this.Orthogonal, this.OrthogonalHeight);
+ }
+
+ public float WorldYAt(float screenY, float zPosition, Layer layer)
+ {
+ if (layer == null || layer.LayerCameraSettings == null)
+ {
+ return WorldYAt(screenY, zPosition, this.Orthogonal, this.OrthogonalHeight);
+ }
+ else
+ {
+ LayerCameraSettings lcs = layer.LayerCameraSettings;
+
+ Camera cameraToUse = layer.CameraBelongingTo;
+
+ if (cameraToUse == null)
+ {
+ cameraToUse = this;
+ }
+
+
+ // If the orthogonal resolution per destination width/height
+ // of the layer matches the Camera's orthogonal per destination, then
+ // we can just use the camera. This is the most common case so we'll just
+ // use that.
+ //return WorldYAt(zPosition, cameraToUse, lcs.Orthogonal, lcs.OrthogonalHeight);
+ // If we have a 2D layer ona 3D camera, then we shouldn't use the Camera's orthogonal values
+ float orthogonalHeightToUse = cameraToUse.OrthogonalHeight;
+
+ // multiplier is used if the orghogonal height of the layer doesn't match the orthogonal height of the
+ // camera. But if we're going to pass the ortho height of the layer, then the multiplier should be 1
+
+ var usedLayerOrtho = lcs.Orthogonal && !cameraToUse.Orthogonal;
+
+ if (usedLayerOrtho)
+ {
+ orthogonalHeightToUse = lcs.OrthogonalHeight;
+ }
+
+ float layerMultiplier = 1;
+ float bottomDestination = lcs.BottomDestination;
+ float topDestination = lcs.TopDestination;
+ if (bottomDestination == -1 || topDestination == -1)
+ {
+ bottomDestination = cameraToUse.BottomDestination;
+ topDestination = cameraToUse.TopDestination;
+ }
+
+ if (lcs.Orthogonal && bottomDestination != topDestination)
+ {
+ layerMultiplier = lcs.OrthogonalHeight / (float)(bottomDestination - topDestination);
+ }
+
+ float cameraMultiplier = 1;
+ if (cameraToUse.Orthogonal && cameraToUse.BottomDestination != cameraToUse.TopDestination)
+ {
+ cameraMultiplier = cameraToUse.OrthogonalHeight / (float)(cameraToUse.BottomDestination - cameraToUse.TopDestination);
+ }
+ layerMultiplier /= cameraMultiplier;
+
+ if (!usedLayerOrtho)
+ {
+ orthogonalHeightToUse *= layerMultiplier;
+ }
+
+ return WorldYAt(screenY, zPosition, lcs.Orthogonal, orthogonalHeightToUse);
+ }
+ }
+
+ public float WorldYAt(float screenY, float zPosition, bool overridingOrthogonal, float overridingOrthogonalHeight)
+ {
+ float screenRelativeY = screenY;
+
+ return WorldYAt(zPosition, overridingOrthogonal, overridingOrthogonalHeight, screenRelativeY);
+ }
+
+ public float WorldYAt(float zPosition, bool orthogonal, float orthogonalHeight, float screenY)
+ {
+ float verticalPercentage = (screenY - this.DestinationRectangle.Top) / (float)this.DestinationRectangle.Height;
+
+ if (!orthogonal)
+ {
+ float absoluteTop = this.AbsoluteTopYEdgeAt(zPosition);
+ float height = this.RelativeYEdgeAt(zPosition) * 2;
+ return absoluteTop - height * verticalPercentage;
+ }
+ else
+ {
+ float yDistanceFromEdge = verticalPercentage * orthogonalHeight;
+ return (this.Y + orthogonalHeight / 2.0f - yDistanceFromEdge);
+ }
+ }
+
+
}
}
\ No newline at end of file
diff --git a/Engines/FlatRedBallXNA/FlatRedBall/FlatRedBallShared.projitems b/Engines/FlatRedBallXNA/FlatRedBall/FlatRedBallShared.projitems
index f2a1184d7..90a59f718 100644
--- a/Engines/FlatRedBallXNA/FlatRedBall/FlatRedBallShared.projitems
+++ b/Engines/FlatRedBallXNA/FlatRedBall/FlatRedBallShared.projitems
@@ -29,7 +29,6 @@
-