(61d00a474) v0.9.7.1
This commit is contained in:
@@ -0,0 +1,327 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
/// <summary>
|
||||
/// Sprite batch extensions for drawing primitive shapes
|
||||
/// Modified from: https://github.com/craftworkgames/MonoGame.Extended/blob/develop/Source/MonoGame.Extended/ShapeExtensions.cs
|
||||
/// </summary>
|
||||
public static class ShapeExtensions
|
||||
{
|
||||
private static Texture2D _whitePixelTexture;
|
||||
|
||||
private static Texture2D GetTexture(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (_whitePixelTexture == null)
|
||||
{
|
||||
CrossThread.RequestExecutionOnMainThread(() =>
|
||||
{
|
||||
_whitePixelTexture = new Texture2D(spriteBatch.GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
|
||||
_whitePixelTexture.SetData(new[] { Color.White });
|
||||
});
|
||||
}
|
||||
|
||||
return _whitePixelTexture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a closed polygon from a <see cref="Polygon" /> shape
|
||||
/// </summary>
|
||||
public static void DrawPolygon(this SpriteBatch spriteBatch, Vector2 position, Polygon polygon, Color color,
|
||||
float thickness = 1f)
|
||||
{
|
||||
DrawPolygon(spriteBatch, position, polygon.Vertices, color, thickness);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a closed polygon from an array of points
|
||||
/// </summary>
|
||||
public static void DrawPolygon(this SpriteBatch spriteBatch, Vector2 offset, IReadOnlyList<Vector2> points, Color color,
|
||||
float thickness = 1f)
|
||||
{
|
||||
if (points.Count == 0)
|
||||
return;
|
||||
|
||||
if (points.Count == 1)
|
||||
{
|
||||
DrawPoint(spriteBatch, points[0], color, (int)thickness);
|
||||
return;
|
||||
}
|
||||
|
||||
var texture = GetTexture(spriteBatch);
|
||||
|
||||
for (var i = 0; i < points.Count - 1; i++)
|
||||
DrawPolygonEdge(spriteBatch, texture, points[i] + offset, points[i + 1] + offset, color, thickness);
|
||||
|
||||
DrawPolygonEdge(spriteBatch, texture, points[points.Count - 1] + offset, points[0] + offset, color,
|
||||
thickness);
|
||||
}
|
||||
|
||||
private static void DrawPolygonEdge(SpriteBatch spriteBatch, Texture2D texture, Vector2 point1, Vector2 point2,
|
||||
Color color, float thickness)
|
||||
{
|
||||
var length = Vector2.Distance(point1, point2);
|
||||
var angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
|
||||
var scale = new Vector2(length, thickness);
|
||||
spriteBatch.Draw(GetTexture(spriteBatch), point1, null, color, angle, Vector2.Zero, scale, SpriteEffects.None, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a line from point1 to point2 with an offset
|
||||
/// </summary>
|
||||
public static void DrawLine(this SpriteBatch spriteBatch, float x1, float y1, float x2, float y2, Color color,
|
||||
float thickness = 1f)
|
||||
{
|
||||
DrawLine(spriteBatch, new Vector2(x1, y1), new Vector2(x2, y2), color, thickness);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a line from point1 to point2 with an offset
|
||||
/// </summary>
|
||||
public static void DrawLine(this SpriteBatch spriteBatch, Vector2 point1, Vector2 point2, Color color,
|
||||
float thickness = 1f)
|
||||
{
|
||||
// calculate the distance between the two vectors
|
||||
var distance = Vector2.Distance(point1, point2);
|
||||
|
||||
// calculate the angle between the two vectors
|
||||
var angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
|
||||
|
||||
DrawLine(spriteBatch, point1, distance, angle, color, thickness);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a line from point1 to point2 with an offset
|
||||
/// </summary>
|
||||
public static void DrawLine(this SpriteBatch spriteBatch, Vector2 point, float length, float angle, Color color,
|
||||
float thickness = 1f)
|
||||
{
|
||||
var origin = new Vector2(0f, 0.5f);
|
||||
var scale = new Vector2(length, thickness);
|
||||
spriteBatch.Draw(GetTexture(spriteBatch), point, null, color, angle, origin, scale, SpriteEffects.None, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a point at the specified x, y position. The center of the point will be at the position.
|
||||
/// </summary>
|
||||
public static void DrawPoint(this SpriteBatch spriteBatch, float x, float y, Color color, float size = 1f)
|
||||
{
|
||||
DrawPoint(spriteBatch, new Vector2(x, y), color, size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a point at the specified position. The center of the point will be at the position.
|
||||
/// </summary>
|
||||
public static void DrawPoint(this SpriteBatch spriteBatch, Vector2 position, Color color, float size = 1f)
|
||||
{
|
||||
var scale = Vector2.One * size;
|
||||
var offset = new Vector2(0.5f) - new Vector2(size * 0.5f);
|
||||
spriteBatch.Draw(GetTexture(spriteBatch), position + offset, null, color, 0.0f, Vector2.Zero, Vector2.One, SpriteEffects.None, 0);
|
||||
}
|
||||
|
||||
public static void DrawCircle(this SpriteBatch spriteBatch, Vector2 center, float radius, int sides, Color color,
|
||||
float thickness = 1f)
|
||||
{
|
||||
DrawPolygon(spriteBatch, center, CreateCircle(radius, sides), color, thickness);
|
||||
}
|
||||
|
||||
public static void DrawCircle(this SpriteBatch spriteBatch, float x, float y, float radius, int sides,
|
||||
Color color, float thickness = 1f)
|
||||
{
|
||||
DrawPolygon(spriteBatch, new Vector2(x, y), CreateCircle(radius, sides), color, thickness);
|
||||
}
|
||||
|
||||
public static void DrawSector(this SpriteBatch spriteBatch, Vector2 center, float radius, float radians, int sides, Color color, float offset = 0, float thickness = 1)
|
||||
{
|
||||
DrawPolygon(spriteBatch, center, CreateSector(radius, sides, radians, offset), color, thickness);
|
||||
}
|
||||
|
||||
private static Vector2[] CreateSector(double radius, int sides, float radians, float offset = 0)
|
||||
{
|
||||
//circle sectors need one extra point at the center
|
||||
var points = new Vector2[radians < MathHelper.TwoPi ? sides + 1 : sides];
|
||||
var step = radians / sides;
|
||||
|
||||
double theta = offset;
|
||||
for (var i = 0; i < sides; i++)
|
||||
{
|
||||
points[i] = new Vector2((float)Math.Cos(theta), (float)Math.Sin(theta)) * (float)radius;
|
||||
theta += step;
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private static Vector2[] CreateCircle(double radius, int sides)
|
||||
{
|
||||
return CreateSector(radius, sides, MathHelper.TwoPi);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Original source: https://github.com/craftworkgames/MonoGame.Extended/blob/develop/Source/MonoGame.Extended/Shapes/Polygon.cs
|
||||
/// </summary>
|
||||
public class Polygon : IEquatable<Polygon>
|
||||
{
|
||||
public Polygon(IEnumerable<Vector2> vertices)
|
||||
{
|
||||
_localVertices = vertices.ToArray();
|
||||
_transformedVertices = _localVertices;
|
||||
_offset = Vector2.Zero;
|
||||
_rotation = 0;
|
||||
_scale = Vector2.One;
|
||||
_isDirty = false;
|
||||
}
|
||||
|
||||
private readonly Vector2[] _localVertices;
|
||||
private Vector2[] _transformedVertices;
|
||||
private Vector2 _offset;
|
||||
private float _rotation;
|
||||
private Vector2 _scale;
|
||||
private bool _isDirty;
|
||||
|
||||
public Vector2[] Vertices
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_isDirty)
|
||||
{
|
||||
_transformedVertices = GetTransformedVertices();
|
||||
_isDirty = false;
|
||||
}
|
||||
|
||||
return _transformedVertices;
|
||||
}
|
||||
}
|
||||
|
||||
public float Left
|
||||
{
|
||||
get { return Vertices.Min(v => v.X); }
|
||||
}
|
||||
|
||||
public float Right
|
||||
{
|
||||
get { return Vertices.Max(v => v.X); }
|
||||
}
|
||||
|
||||
public float Top
|
||||
{
|
||||
get { return Vertices.Min(v => v.Y); }
|
||||
}
|
||||
|
||||
public float Bottom
|
||||
{
|
||||
get { return Vertices.Max(v => v.Y); }
|
||||
}
|
||||
|
||||
public void Offset(Vector2 amount)
|
||||
{
|
||||
_offset += amount;
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
public void Rotate(float amount)
|
||||
{
|
||||
_rotation += amount;
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
public void Scale(Vector2 amount)
|
||||
{
|
||||
_scale += amount;
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
private Vector2[] GetTransformedVertices()
|
||||
{
|
||||
var newVertices = new Vector2[_localVertices.Length];
|
||||
var isScaled = _scale != Vector2.One;
|
||||
|
||||
for (var i = 0; i < _localVertices.Length; i++)
|
||||
{
|
||||
var p = _localVertices[i];
|
||||
|
||||
if (isScaled)
|
||||
p *= _scale;
|
||||
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||
if (_rotation != 0)
|
||||
{
|
||||
var cos = (float)Math.Cos(_rotation);
|
||||
var sin = (float)Math.Sin(_rotation);
|
||||
p = new Vector2(cos * p.X - sin * p.Y, sin * p.X + cos * p.Y);
|
||||
}
|
||||
|
||||
newVertices[i] = p + _offset;
|
||||
}
|
||||
|
||||
return newVertices;
|
||||
}
|
||||
|
||||
public Polygon TransformedCopy(Vector2 offset, float rotation, Vector2 scale)
|
||||
{
|
||||
var polygon = new Polygon(_localVertices);
|
||||
polygon.Offset(offset);
|
||||
polygon.Rotate(rotation);
|
||||
polygon.Scale(scale - Vector2.One);
|
||||
return new Polygon(polygon.Vertices);
|
||||
}
|
||||
|
||||
public bool Contains(Vector2 point)
|
||||
{
|
||||
return Contains(point.X, point.Y);
|
||||
}
|
||||
|
||||
public bool Contains(float x, float y)
|
||||
{
|
||||
var intersects = 0;
|
||||
var vertices = Vertices;
|
||||
|
||||
for (var i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
var x1 = vertices[i].X;
|
||||
var y1 = vertices[i].Y;
|
||||
var x2 = vertices[(i + 1) % vertices.Length].X;
|
||||
var y2 = vertices[(i + 1) % vertices.Length].Y;
|
||||
|
||||
if ((((y1 <= y) && (y < y2)) || ((y2 <= y) && (y < y1))) && (x < (x2 - x1) / (y2 - y1) * (y - y1) + x1))
|
||||
intersects++;
|
||||
}
|
||||
|
||||
return (intersects & 1) == 1;
|
||||
}
|
||||
|
||||
public static bool operator ==(Polygon a, Polygon b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator !=(Polygon a, Polygon b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
return obj is Polygon && Equals((Polygon)obj);
|
||||
}
|
||||
|
||||
public bool Equals(Polygon other)
|
||||
{
|
||||
return Vertices.SequenceEqual(other.Vertices);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return Vertices.Aggregate(27, (current, v) => current + 13 * current + v.GetHashCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user