A game framework written with osu! in mind.
at master 245 lines 14 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using System.ComponentModel; 6using System.Diagnostics.CodeAnalysis; 7using System.Globalization; 8using System.Runtime.InteropServices; 9using osuTK; 10 11namespace osu.Framework.Graphics.Primitives 12{ 13 /// <summary>Stores a set of four integer numbers that represent the location and size of a rectangle. The code was duplicated from <see cref="System.Drawing.Rectangle"/>.</summary> 14 /// <filterpriority>1</filterpriority> 15 [Serializable, StructLayout(LayoutKind.Sequential)] 16 public struct RectangleI : IEquatable<RectangleI> 17 { 18 /// <summary>Represents an instance of the <see cref="RectangleI"/> class with its members uninitialized.</summary> 19 /// <filterpriority>1</filterpriority> 20 public static readonly RectangleI Empty; 21 22 public int X; 23 public int Y; 24 25 public int Width; 26 public int Height; 27 28 /// <summary>Initializes a new instance of the <see cref="RectangleI"/> class with the specified location and size.</summary> 29 /// <param name="y">The y-coordinate of the upper-left corner of the rectangle. </param> 30 /// <param name="width">The width of the rectangle. </param> 31 /// <param name="height">The height of the rectangle. </param> 32 /// <param name="x">The x-coordinate of the upper-left corner of the rectangle. </param> 33 public RectangleI(int x, int y, int width, int height) 34 { 35 X = x; 36 Y = y; 37 Width = width; 38 Height = height; 39 } 40 41 /// <summary>Gets or sets the coordinates of the upper-left corner of this <see cref="RectangleI"/> structure.</summary> 42 /// <returns>A <see cref="osuTK.Vector2"/> that represents the upper-left corner of this <see cref="RectangleI"/> structure.</returns> 43 /// <filterpriority>1</filterpriority> 44 [Browsable(false)] 45 public Vector2I Location => new Vector2I(X, Y); 46 47 /// <summary>Gets or sets the size of this <see cref="RectangleI"/>.</summary> 48 /// <returns>A <see cref="osuTK.Vector2"/> that represents the width and height of this <see cref="RectangleI"/> structure.</returns> 49 /// <filterpriority>1</filterpriority> 50 [Browsable(false)] 51 public Vector2I Size => new Vector2I(Width, Height); 52 53 /// <summary>Gets the y-coordinate of the top edge of this <see cref="RectangleI"/> structure.</summary> 54 /// <returns>The y-coordinate of the top edge of this <see cref="RectangleI"/> structure.</returns> 55 /// <filterpriority>1</filterpriority> 56 [Browsable(false)] 57 public int Left => X; 58 59 /// <summary>Gets the y-coordinate of the top edge of this <see cref="RectangleI"/> structure.</summary> 60 /// <returns>The y-coordinate of the top edge of this <see cref="RectangleI"/> structure.</returns> 61 /// <filterpriority>1</filterpriority> 62 [Browsable(false)] 63 public int Top => Y; 64 65 /// <summary>Gets the x-coordinate that is the sum of <see cref="X"/> and <see cref="Width"/> of this <see cref="RectangleI"/> structure.</summary> 66 /// <returns>The x-coordinate that is the sum of <see cref="X"/> and <see cref="Width"/> of this <see cref="RectangleI"/> structure.</returns> 67 /// <filterpriority>1</filterpriority> 68 [Browsable(false)] 69 public int Right => X + Width; 70 71 /// <summary>Gets the y-coordinate that is the sum of <see cref="Y"/> and <see cref="Height"/> of this <see cref="RectangleI"/> structure.</summary> 72 /// <returns>The y-coordinate that is the sum of <see cref="Y"/> and <see cref="Height"/> of this <see cref="RectangleI"/> structure.</returns> 73 /// <filterpriority>1</filterpriority> 74 [Browsable(false)] 75 public int Bottom => Y + Height; 76 77 [Browsable(false)] 78 public Vector2I TopLeft => new Vector2I(Left, Top); 79 80 [Browsable(false)] 81 public Vector2I TopRight => new Vector2I(Right, Top); 82 83 [Browsable(false)] 84 public Vector2I BottomLeft => new Vector2I(Left, Bottom); 85 86 [Browsable(false)] 87 public Vector2I BottomRight => new Vector2I(Right, Bottom); 88 89 /// <summary>Tests whether the <see cref="Width"/> or <see cref="Height"/> property of this <see cref="RectangleI"/> has a value of zero.</summary> 90 /// <returns>This property returns true if the <see cref="Width"/> or <see cref="Height"/> property of this <see cref="RectangleI"/> has a value of zero; otherwise, false.</returns> 91 /// <filterpriority>1</filterpriority> 92 [Browsable(false)] 93 public bool IsEmpty => Width <= 0 || Height <= 0; 94 95 /// <summary>Tests whether obj is a <see cref="RectangleI"/> with the same location and size of this <see cref="RectangleI"/>.</summary> 96 /// <returns>This method returns true if obj is a <see cref="RectangleI"/> and its X, Y, Width, and Height properties are equal to the corresponding properties of this <see cref="RectangleI"/>; otherwise, false.</returns> 97 /// <param name="obj">The <see cref="object"/> to test. </param> 98 /// <filterpriority>1</filterpriority> 99 public override bool Equals(object obj) => obj is RectangleI rec && Equals(rec); 100 101 /// <summary>Tests whether two <see cref="RectangleI"/> structures have equal location and size.</summary> 102 /// <returns>This operator returns true if the two specified <see cref="RectangleI"/> structures have equal <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties.</returns> 103 /// <param name="right">The <see cref="RectangleI"/> structure that is to the right of the equality operator. </param> 104 /// <param name="left">The <see cref="RectangleI"/> structure that is to the left of the equality operator. </param> 105 /// <filterpriority>3</filterpriority> 106 public static bool operator ==(RectangleI left, RectangleI right) => left.X == right.X && left.Y == right.Y && left.Width == right.Width && left.Height == right.Height; 107 108 /// <summary>Tests whether two <see cref="RectangleI"/> structures differ in location or size.</summary> 109 /// <returns>This operator returns true if any of the <see cref="X"/> , <see cref="Y"/>, <see cref="Width"/>, or <see cref="Height"/> properties of the two <see cref="RectangleI"/> structures are unequal; otherwise false.</returns> 110 /// <param name="right">The <see cref="RectangleI"/> structure that is to the right of the inequality operator. </param> 111 /// <param name="left">The <see cref="RectangleI"/> structure that is to the left of the inequality operator. </param> 112 /// <filterpriority>3</filterpriority> 113 public static bool operator !=(RectangleI left, RectangleI right) => !(left == right); 114 115 /// <summary>Determines if the specified point is contained within this <see cref="RectangleI"/> structure.</summary> 116 /// <returns>This method returns true if the point defined by x and y is contained within this <see cref="RectangleI"/> structure; otherwise false.</returns> 117 /// <param name="y">The y-coordinate of the point to test. </param> 118 /// <param name="x">The x-coordinate of the point to test. </param> 119 /// <filterpriority>1</filterpriority> 120 public bool Contains(float x, float y) => X <= x && x < X + Width && Y <= y && y < Y + Height; 121 122 public bool Contains(Vector2 pt) => Contains(pt.X, pt.Y); 123 124 public bool Contains(int x, int y) => X <= x && x < X + Width && Y <= y && y < Y + Height; 125 126 public bool Contains(Vector2I pt) => Contains(pt.X, pt.Y); 127 128 /// <summary>Determines if the rectangular region represented by rect is entirely contained within this <see cref="RectangleI"/> structure.</summary> 129 /// <returns>This method returns true if the rectangular region represented by rect is entirely contained within the rectangular region represented by this <see cref="RectangleI"/>; otherwise false.</returns> 130 /// <param name="rect">The <see cref="RectangleI"/> to test. </param> 131 /// <filterpriority>1</filterpriority> 132 public bool Contains(RectangleI rect) => 133 X <= rect.X && rect.X + rect.Width <= X + Width && Y <= rect.Y && 134 rect.Y + rect.Height <= Y + Height; 135 136 /// <summary>Gets the hash code for this <see cref="RectangleI"/> structure. For information about the use of hash codes, see Object.GetHashCode.</summary> 137 /// <returns>The hash code for this <see cref="RectangleI"/>.</returns> 138 /// <filterpriority>1</filterpriority> 139 [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] 140 public override int GetHashCode() => (int)(((uint)X ^ ((uint)Y << 13)) | (((uint)Y >> 0x13) ^ ((uint)Width << 0x1a)) | (((uint)Width >> 6) ^ ((uint)Height << 7)) | ((uint)Height >> 0x19)); 141 142 public int Area => Width * Height; 143 144 public RectangleI WithPositiveExtent 145 { 146 get 147 { 148 RectangleI result = this; 149 150 if (result.Width < 0) 151 { 152 result.Width = -result.Width; 153 result.X -= result.Width; 154 } 155 156 if (Height < 0) 157 { 158 result.Height = -result.Height; 159 result.Y -= result.Height; 160 } 161 162 return result; 163 } 164 } 165 166 public RectangleI Inflate(int amount) => Inflate(new Vector2I(amount)); 167 168 public RectangleI Inflate(Vector2I amount) => Inflate(amount.X, amount.X, amount.Y, amount.Y); 169 170 public RectangleI Inflate(int left, int right, int top, int bottom) => new RectangleI( 171 X - left, 172 Y - top, 173 Width + left + right, 174 Height + top + bottom); 175 176 public RectangleI Shrink(int amount) => Shrink(new Vector2I(amount)); 177 178 public RectangleI Shrink(Vector2I amount) => Shrink(amount.X, amount.X, amount.Y, amount.Y); 179 180 public RectangleI Shrink(int left, int right, int top, int bottom) => Inflate(-left, -right, -top, -bottom); 181 182 /// <summary>Intersects this <see cref="RectangleI"/> structure with the specified <see cref="RectangleI"/> structure.</summary> 183 /// <returns>The intersected rectangle.</returns> 184 /// <param name="rect">The rectangle to intersect. </param> 185 /// <filterpriority>1</filterpriority> 186 public RectangleI Intersect(RectangleI rect) => Intersect(rect, this); 187 188 /// <summary>Returns a <see cref="RectangleI"/> structure that represents the intersection of two rectangles. If there is no intersection, and empty <see cref="RectangleI"/> is returned.</summary> 189 /// <returns>A third <see cref="RectangleI"/> structure the size of which represents the overlapped area of the two specified rectangles.</returns> 190 /// <param name="a">A rectangle to intersect. </param> 191 /// <param name="b">A rectangle to intersect. </param> 192 /// <filterpriority>1</filterpriority> 193 public static RectangleI Intersect(RectangleI a, RectangleI b) 194 { 195 int x = Math.Max(a.X, b.X); 196 int num2 = Math.Min(a.X + a.Width, b.X + b.Width); 197 int y = Math.Max(a.Y, b.Y); 198 int num4 = Math.Min(a.Y + a.Height, b.Y + b.Height); 199 if (num2 >= x && num4 >= y) 200 return new RectangleI(x, y, num2 - x, num4 - y); 201 202 return Empty; 203 } 204 205 /// <summary>Determines if this rectangle intersects with rect.</summary> 206 /// <returns>This method returns true if there is any intersection.</returns> 207 /// <param name="rect">The rectangle to test. </param> 208 /// <filterpriority>1</filterpriority> 209 public bool IntersectsWith(RectangleI rect) => 210 rect.X <= X + Width && X <= rect.X + rect.Width && rect.Y <= Y + Height && Y <= rect.Y + rect.Height; 211 212 /// <summary>Creates the smallest possible third rectangle that can contain both of two rectangles that form a union.</summary> 213 /// <returns>A third <see cref="RectangleI"/> structure that contains both of the two rectangles that form the union.</returns> 214 /// <param name="a">A rectangle to union. </param> 215 /// <param name="b">A rectangle to union. </param> 216 /// <filterpriority>1</filterpriority> 217 public static RectangleI Union(RectangleI a, RectangleI b) 218 { 219 int x = Math.Min(a.X, b.X); 220 int num2 = Math.Max(a.X + a.Width, b.X + b.Width); 221 int y = Math.Min(a.Y, b.Y); 222 int num4 = Math.Max(a.Y + a.Height, b.Y + b.Height); 223 return new RectangleI(x, y, num2 - x, num4 - y); 224 } 225 226 /// <summary>Adjusts the location of this rectangle by the specified amount.</summary> 227 /// <returns>This method does not return a value.</returns> 228 /// <param name="y">The amount to offset the location vertically. </param> 229 /// <param name="x">The amount to offset the location horizontally. </param> 230 /// <filterpriority>1</filterpriority> 231 public RectangleI Offset(int x, int y) => new RectangleI(X + x, Y + y, Width, Height); 232 233 public static implicit operator RectangleI(RectangleF r) => r.AABB; 234 235 /// <summary>Converts the Location and <see cref="Size"/> of this <see cref="RectangleI"/> to a human-readable string.</summary> 236 /// <returns>A string that contains the position, width, and height of this <see cref="RectangleI"/> structure¾for example, "{X=20, Y=20, Width=100, Height=50}".</returns> 237 /// <filterpriority>1</filterpriority> 238 public override string ToString() => $"X={X.ToString(CultureInfo.CurrentCulture)}, " 239 + $"Y={Y.ToString(CultureInfo.CurrentCulture)}, " 240 + $"Width={Width.ToString(CultureInfo.CurrentCulture)}, " 241 + $"Height={Height.ToString(CultureInfo.CurrentCulture)}"; 242 243 public bool Equals(RectangleI other) => X == other.X && Y == other.Y && Width == other.Width && Height == other.Height; 244 } 245}