protected override void Render(IDrawer drawer) { TopLeftRectangle cameraRectangle = drawer.DisplayedRectangle.BoundingBox; TopLeftRectangle drawnRectangle = Grid.BoundingBox; if (!drawnRectangle.Intersects(cameraRectangle, out TopLeftRectangle visibleRectangle)) { return; } IEnumerable <int[]> indexIntersection = Grid.IndexIntersection(visibleRectangle); foreach (int[] indexes in indexIntersection) { if (!RenderingBehaviour(Grid[indexes], this)) { continue; } Vector2 position = Grid.ToWorldPoint(indexes); if (SpriteTransformer != null) { drawer.SpriteBatchStack.Current.Draw(Source.Texture, position + Transformation.Translation, Source.Rectangle, SpriteTransformer.Color, SceneNode.Rotation + Transformation.Rotation, SpriteTransformer.Origin, SceneNode.Scale * Transformation.Scale * SpriteTransformer.Scale, SpriteTransformer.Effects, RenderDepth); } else { drawer.SpriteBatchStack.Current.Draw(Source.Texture, position + Transformation.Translation, Source.Rectangle, Color.White, SceneNode.Rotation + Transformation.Rotation, Source.GetDefaultOrigin(), SceneNode.Scale * Transformation.Scale, SpriteEffects.None, RenderDepth); } } }
static public IEnumerable <int[]> IndexIntersection <TOther>( this IGrid grid, IntersectionDelegate <TopLeftRectangle, TOther> intersectionDelegate, TOther other, Func <int, int, bool> cellSelector = null) where TOther : IShape { // TODO: Use better grid-shape intersection algorithm Rectangle gridBoundingBox = MathUtils.GetBoundingBox(other.BoundingBox.Vertices.Select(grid.ToGridPoint)).ClampToRectangle(grid.IndexesBounds()); int[] indexes = new int[2]; for (indexes[0] = gridBoundingBox.Y; indexes[0] <= gridBoundingBox.Bottom; indexes[0]++) { for (indexes[1] = gridBoundingBox.X; indexes[1] <= gridBoundingBox.Right; indexes[1]++) { if (!(cellSelector?.Invoke(indexes[0], indexes[1]) ?? true)) { continue; } var cellRectangle = new TopLeftRectangle(grid.ToWorldPoint(indexes), grid.Delta); if (intersectionDelegate(cellRectangle, other)) { yield return(indexes); } } } }
static public void GetBoundingBox() { var pointA = new Vector2(-2, 1); var pointB = new Vector2(2, 3); var pointC = new Vector2(-3, -4); TopLeftRectangle result = MathUtils.GetBoundingBox(pointA, pointB, pointC); Assert.AreEqual(-3, result.Left); Assert.AreEqual(2, result.Right); Assert.AreEqual(-4, result.Top); Assert.AreEqual(3, result.Bottom); result = MathUtils.GetBoundingBox((IEnumerable <Vector2>)null); Assert.AreEqual(0, result.Left); Assert.AreEqual(0, result.Right); Assert.AreEqual(0, result.Top); Assert.AreEqual(0, result.Bottom); result = MathUtils.GetBoundingBox(new Vector2[0]); Assert.AreEqual(0, result.Left); Assert.AreEqual(0, result.Right); Assert.AreEqual(0, result.Top); Assert.AreEqual(0, result.Bottom); var rectangleA = new TopLeftRectangle(-3, -2, 1, 1); var rectangleB = new TopLeftRectangle(2, 1, 3, 3); var rectangleC = new TopLeftRectangle(-4, -5, 2, 10); result = MathUtils.GetBoundingBox(rectangleA, rectangleB, rectangleC); Assert.AreEqual(-4, result.Left); Assert.AreEqual(5, result.Right); Assert.AreEqual(-5, result.Top); Assert.AreEqual(5, result.Bottom); result = MathUtils.GetBoundingBox((IEnumerable <TopLeftRectangle>)null); Assert.AreEqual(0, result.Left); Assert.AreEqual(0, result.Right); Assert.AreEqual(0, result.Top); Assert.AreEqual(0, result.Bottom); result = MathUtils.GetBoundingBox(new TopLeftRectangle[0]); Assert.AreEqual(0, result.Left); Assert.AreEqual(0, result.Right); Assert.AreEqual(0, result.Top); Assert.AreEqual(0, result.Bottom); var circleA = new Circle(new Vector2(-2, -2), 3); var circleB = new Circle(new Vector2(2, 2), 5); var circleC = new Circle(new Vector2(5, 8), 2); result = MathUtils.GetBoundingBox(circleA, circleB, circleC); Assert.AreEqual(-5, result.Left); Assert.AreEqual(7, result.Right); Assert.AreEqual(-5, result.Top); Assert.AreEqual(10, result.Bottom); }
protected override void Render(IDrawer drawer) { TopLeftRectangle cameraRectangle = drawer.DisplayedRectangle.BoundingBox; TopLeftRectangle drawnRectangle = _fillingRectangle.Rectangle.BoundingBox; if (!drawnRectangle.Intersects(cameraRectangle, out TopLeftRectangle visibleRectangle)) { return; } TopLeftRectangle sourceRectangle = Source.GetDrawnRectangle().ToFloats(); Vector2 diff = cameraRectangle.Position - drawnRectangle.Position; Vector2 sourcePatchInit = new Vector2(MathHelper.Max(diff.X, 0), MathHelper.Max(diff.Y, 0)); Vector2 sourcePatchOrigin = sourcePatchInit; float y = 0; while (y < visibleRectangle.Height) { float sourceRemainingHeight = sourceRectangle.Height - sourcePatchOrigin.Y; float destinationRemainingHeight = visibleRectangle.Height - y; float sourcePatchHeight = MathHelper.Min(sourceRemainingHeight, destinationRemainingHeight); sourcePatchOrigin.X = sourcePatchInit.X; float x = 0; while (x < visibleRectangle.Width) { float sourceRemainingWidth = sourceRectangle.Width - sourcePatchOrigin.X; float destinationRemainingWidth = visibleRectangle.Width - x; float sourcePatchWidth = MathHelper.Min(sourceRemainingWidth, destinationRemainingWidth); Vector2 position = visibleRectangle.Position + (SceneNode.Transform(new Vector2(x, y)) - SceneNode.Position); var sourcePatch = new TopLeftRectangle(sourcePatchOrigin, new Vector2(sourcePatchWidth, sourcePatchHeight)); if (SpriteTransformer != null) { drawer.SpriteBatchStack.Current.Draw(Source.Texture, position, sourcePatch.ToIntegers(), SpriteTransformer.Color, SceneNode.Rotation, Vector2.Zero, SceneNode.Scale * SpriteTransformer.Scale, SpriteTransformer.Effects, SceneNode.Depth); } else { drawer.SpriteBatchStack.Current.Draw(Source.Texture, position, sourcePatch.ToIntegers(), Color.White, SceneNode.Rotation, Vector2.Zero, SceneNode.Scale, SpriteEffects.None, SceneNode.Depth); } x += sourcePatchWidth; sourcePatchOrigin.X = sourceRectangle.Position.X; } y += sourcePatchHeight; sourcePatchOrigin.Y = sourceRectangle.Position.Y; } }
public Vector2[] GetVertexTextureCoordinates(IReadOnlyList <Vector2> vertices) { var textureCoordinates = new Vector2[vertices.Count]; TopLeftRectangle boundingBox = MathUtils.GetBoundingBox(vertices); for (int i = 0; i < textureCoordinates.Length; i++) { textureCoordinates[i] = vertices[i].Rescale(boundingBox, new TopLeftRectangle(0, 0, 1, 1)); } return(textureCoordinates); }
public IEnumerable <IPartitioner> Subdivide() { for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { var rectangle = new TopLeftRectangle { Position = BoundingBox.Position + new Vector2(j, i) * BoundingBox.Size / 2, Size = BoundingBox.Size / 2 }; yield return(new QuadtreePartitioner(rectangle, Capacity)); } } }
public IEnumerable <IWriteableSpace <T> > GetAllPartitionsInRange(TopLeftRectangle range) { if (_partitioner != null && !_partitioner.Intersects(range)) { yield break; } if (_partitions.Count == 0) { yield return(this); yield break; } foreach (IWriteableSpace <T> partition in _partitions) { foreach (IWriteableSpace <T> result in partition.GetAllPartitionsInRange(range)) { yield return(result); } } }
IEnumerable <ISpace> ISpace.GetAllPartitionsInRange(TopLeftRectangle range) => ((ISpace)_space).GetAllPartitionsInRange(range);
public IEnumerable <ISpace <T> > GetAllPartitionsInRange(TopLeftRectangle range) => ((ISpace <T>)_space).GetAllPartitionsInRange(range);
public QuadtreePartitioner(TopLeftRectangle bounds, int capacity) { BoundingBox = bounds; Capacity = capacity; }
static public Quad Transform(this ITransformer transformer, TopLeftRectangle topLeftRectangle) { return(new Quad(transformer.Transform(topLeftRectangle.Position), transformer.Transform(topLeftRectangle.P1), transformer.Transform(topLeftRectangle.P2))); }
public IEnumerable <ISpace> GetAllPartitionsInRange(TopLeftRectangle range) => _space.GetAllPartitionsInRange(range);
IEnumerable <ISpace> ISpace.GetAllPartitionsInRange(TopLeftRectangle range) { return(GetAllPartitionsInRange(range)); }
static public bool IsShapeCollidingGrid <TShape>(CollisionDelegate <TShape, TopLeftRectangle> rectangleCollisionDelegate, ICollider <TShape> shapeCollider, IGridCollider gridCollider, out Collision collision) where TShape : IShape { IEnumerable <int[]> shapeGridBox = gridCollider.Grid.IndexIntersection( (x, y) => rectangleCollisionDelegate(y, x, out _), shapeCollider.Shape, (i, j) => gridCollider.IsCollidableCase(shapeCollider, i, j)); foreach (int[] indexes in shapeGridBox) { int i = indexes[0]; int j = indexes[1]; var rectangle = new TopLeftRectangle(gridCollider.Grid.ToWorldPoint(i, j), gridCollider.Grid.Delta); bool colliding = false; for (int x = -1; x <= 1 && !colliding; x++) { for (int y = -1; y <= 1 && !colliding; y++) { if ((x + y) % 2 == 0) { continue; } if (!gridCollider.Grid.ContainsPoint(i + y, j + x) || !gridCollider.IsCollidableCase(shapeCollider, i + y, j + x)) { continue; } var otherCase = new TopLeftRectangle(gridCollider.Grid.ToWorldPoint(i + y, j + x), gridCollider.Grid.Delta); if (!rectangleCollisionDelegate(shapeCollider.Shape, otherCase, out _)) { continue; } rectangle = new TopLeftRectangle { Position = (gridCollider.Grid.ToWorldPoint(i, j) + gridCollider.Grid.ToWorldPoint(i + y, j + x)) * 0.5f, Size = gridCollider.Grid.Delta + gridCollider.Grid.Delta.Multiply(System.Math.Abs(x), System.Math.Abs(y)) }; colliding = true; } } if (!rectangleCollisionDelegate(shapeCollider.Shape, rectangle, out Vector2 correction)) { continue; } collision = new Collision { Sender = shapeCollider, OtherCollider = gridCollider, Correction = correction }; return(true); } collision = new Collision(); return(false); }
static public Rectangle ToIntegers(this TopLeftRectangle value) { return(new Rectangle((int)value.Left, (int)value.Top, (int)value.Width, (int)value.Height)); }