// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SharpDX.Mathematics.Interop; namespace SharpDX { /// /// Defines the viewport dimensions using float coordinates for (X,Y,Width,Height). /// [StructLayout(LayoutKind.Sequential, Pack = 4)] public struct ViewportF : IEquatable { /// /// Position of the pixel coordinate of the upper-left corner of the viewport. /// public float X; /// /// Position of the pixel coordinate of the upper-left corner of the viewport. /// public float Y; /// /// Width dimension of the viewport. /// public float Width; /// /// Height dimension of the viewport. /// public float Height; /// /// Gets or sets the minimum depth of the clip volume. /// public float MinDepth; /// /// Gets or sets the maximum depth of the clip volume. /// public float MaxDepth; /// /// Initializes a new instance of the struct. /// /// The x coordinate of the upper-left corner of the viewport in pixels. /// The y coordinate of the upper-left corner of the viewport in pixels. /// The width of the viewport in pixels. /// The height of the viewport in pixels. public ViewportF(float x, float y, float width, float height) { X = x; Y = y; Width = width; Height = height; MinDepth = 0f; MaxDepth = 1f; } /// /// Initializes a new instance of the struct. /// /// The x coordinate of the upper-left corner of the viewport in pixels. /// The y coordinate of the upper-left corner of the viewport in pixels. /// The width of the viewport in pixels. /// The height of the viewport in pixels. /// The minimum depth of the clip volume. /// The maximum depth of the clip volume. public ViewportF(float x, float y, float width, float height, float minDepth, float maxDepth) { X = x; Y = y; Width = width; Height = height; MinDepth = minDepth; MaxDepth = maxDepth; } /// /// Initializes a new instance of the struct. /// /// A bounding box that defines the location and size of the viewport in a render target. public ViewportF(RectangleF bounds) { X = bounds.X; Y = bounds.Y; Width = bounds.Width; Height = bounds.Height; MinDepth = 0f; MaxDepth = 1f; } /// /// Gets the size of this resource. /// /// The bounds. public RectangleF Bounds { get { return new RectangleF(X, Y, Width, Height); } set { X = value.X; Y = value.Y; Width = value.Width; Height = value.Height; } } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// /// true if the specified is equal to this instance; otherwise, false. /// public bool Equals(ref ViewportF other) { return MathUtil.NearEqual(X, other.X) && MathUtil.NearEqual(Y, other.Y) && MathUtil.NearEqual(Width, other.Width) && MathUtil.NearEqual(Height, other.Height) && MathUtil.NearEqual(MinDepth, other.MinDepth) && MathUtil.NearEqual(MaxDepth, other.MaxDepth); } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// /// true if the specified is equal to this instance; otherwise, false. /// [MethodImpl((MethodImplOptions)0x100)] // MethodImplOptions.AggressiveInlining public bool Equals(ViewportF other) { return Equals(ref other); } /// /// Determines whether the specified object is equal to this instance. /// /// The object to compare with this instance. /// /// true if the specified object is equal to this instance; otherwise, false. /// public override bool Equals(object obj) { if(!(obj is ViewportF)) return false; var strongValue = (ViewportF)obj; return Equals(ref strongValue); } /// /// Returns a hash code for this instance. /// /// /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// public override int GetHashCode() { unchecked { int hashCode = X.GetHashCode(); hashCode = (hashCode * 397) ^ Y.GetHashCode(); hashCode = (hashCode * 397) ^ Width.GetHashCode(); hashCode = (hashCode * 397) ^ Height.GetHashCode(); hashCode = (hashCode * 397) ^ MinDepth.GetHashCode(); hashCode = (hashCode * 397) ^ MaxDepth.GetHashCode(); return hashCode; } } /// /// Implements the operator ==. /// /// The left. /// The right. /// The result of the operator. [MethodImpl((MethodImplOptions)0x100)] // MethodImplOptions.AggressiveInlining public static bool operator ==(ViewportF left, ViewportF right) { return left.Equals(ref right); } /// /// Implements the operator !=. /// /// The left. /// The right. /// The result of the operator. [MethodImpl((MethodImplOptions)0x100)] // MethodImplOptions.AggressiveInlining public static bool operator !=(ViewportF left, ViewportF right) { return !left.Equals(ref right); } /// /// Retrieves a string representation of this object. /// /// A that represents this instance. public override string ToString() { return string.Format(CultureInfo.CurrentCulture, "{{X:{0} Y:{1} Width:{2} Height:{3} MinDepth:{4} MaxDepth:{5}}}", X, Y, Width, Height, MinDepth, MaxDepth); } /// /// Projects a 3D vector from object space into screen space. /// /// The vector to project. /// The projection matrix. /// The view matrix. /// The world matrix. /// The projected vector./returns> public Vector3 Project(Vector3 source, Matrix projection, Matrix view, Matrix world) { Matrix matrix; Matrix.Multiply(ref world, ref view, out matrix); Matrix.Multiply(ref matrix, ref projection, out matrix); Vector3 vector; Project(ref source, ref matrix, out vector); return vector; } /// /// Projects a 3D vector from object space into screen space. /// /// The vector to project. /// A combined WorldViewProjection matrix. /// The projected vector. public void Project(ref Vector3 source, ref Matrix matrix, out Vector3 vector) { Vector3.Transform(ref source, ref matrix, out vector); float a = (((source.X * matrix.M14) + (source.Y * matrix.M24)) + (source.Z * matrix.M34)) + matrix.M44; if (!MathUtil.IsOne(a)) { vector = (vector / a); } vector.X = (((vector.X + 1f) * 0.5f) * Width) + X; vector.Y = (((-vector.Y + 1f) * 0.5f) * Height) + Y; vector.Z = (vector.Z * (MaxDepth - MinDepth)) + MinDepth; } /// /// Converts a screen space point into a corresponding point in world space. /// /// The vector to project. /// The projection matrix. /// The view matrix. /// The world matrix. /// The unprojected Vector. public Vector3 Unproject(Vector3 source, Matrix projection, Matrix view, Matrix world) { Matrix matrix; Matrix.Multiply(ref world, ref view, out matrix); Matrix.Multiply(ref matrix, ref projection, out matrix); Matrix.Invert(ref matrix, out matrix); Vector3 vector; Unproject(ref source, ref matrix, out vector); return vector; } /// /// Converts a screen space point into a corresponding point in world space. /// /// The vector to project. /// An inverted combined WorldViewProjection matrix. /// The unprojected vector. public void Unproject(ref Vector3 source, ref Matrix matrix, out Vector3 vector) { vector.X = (((source.X - X) / (Width)) * 2f) - 1f; vector.Y = -((((source.Y - Y) / (Height)) * 2f) - 1f); vector.Z = (source.Z - MinDepth) / (MaxDepth - MinDepth); float a = (((vector.X * matrix.M14) + (vector.Y * matrix.M24)) + (vector.Z * matrix.M34)) + matrix.M44; Vector3.Transform(ref vector, ref matrix, out vector); if (!MathUtil.IsOne(a)) { vector = (vector / a); } } /// /// Gets the aspect ratio used by the viewport. /// /// The aspect ratio. public float AspectRatio { get { if (!MathUtil.IsZero(Height)) { return Width / Height; } return 0f; } } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static implicit operator ViewportF(Viewport value) { return new ViewportF(value.X, value.Y, value.Width, value.Height, value.MinDepth, value.MaxDepth); } /// /// Performs an implicit conversion from to . /// /// The value. /// The result of the conversion. public unsafe static implicit operator RawViewportF(ViewportF value) { return *(RawViewportF*)&value; } /// /// Performs an implicit conversion from to . /// /// The value. /// The result of the conversion. public unsafe static implicit operator ViewportF(RawViewportF value) { return *(ViewportF*)&value; } } }