private static byte[] ConvertSocketPointsToBytes(SimplePoint[] points) { var pointBytes = new List<byte>(points.Length * 4); foreach (var point in points) { pointBytes.AddRange(BitConverter.GetBytes(point.X)); pointBytes.AddRange(BitConverter.GetBytes(point.Y)); } return pointBytes.ToArray(); }
public CenterMapSocketObject(SimplePoint centerMap) : base(SocketConstants.SocketAction.CenterMap) { CenterMap = centerMap; }
private void connection_OnCenterMapReceived(SimplePoint centerMap) { // Take the point that we want to show, and center it on the client's UI. SetScroll(centerMap.X - this.Width / 2, centerMap.Y - this.Height / 2); }
public void Add(SimplePoint point) { _points.AddLast(point); }
public virtual void SetCenterMap(SimplePoint centerMap) { this.SetCenterMap(centerMap, false); }
protected void SetCenterMap(SimplePoint centerMap, bool animate) { // Take the point that we want to show, and center it on the client's UI. this.BeginInvoke(new Action(() => { // The point that came in is raw on the map... var x = centerMap.X; var y = centerMap.Y; // We also need to account for the client's zoom factor (gives us the X/Y of a Zoomed map), to which we then "unzoom" the X/Y back to the raw map location for scroll purposes. x = (int)(((x * AssignedZoomFactor) - (this.VisibleSize.Width / 2.0d)) * this.InverseZoomFactor); y = (int)(((y * AssignedZoomFactor) - (this.VisibleSize.Height / 2.0d)) * this.InverseZoomFactor); if (!animate) { SetScroll(x, y); return; } // If we're already doing a Center Map fade, we're going to simply pop out the old values. It may glitch a bit to the end user, but the end result will be fine. // Our timer will go from True/0.0 to True/1.0, then flip to False/1.0 down to False/0.0 this.centerMapFadingTimer.Tag = new SimplePoint(x, y); this.centerMapFadingValues = new Tuple<bool, float>(true, 0.0f); this.centerMapFadingTimer.Start(); })); }
public void WriteCenterMap(SimplePoint point) { if (ClientsCount == 0) return; EnqueueWrite(new CenterMapSocketObject(point)); }
private void ctlMiniMap_OnNewCenterMap(SimplePoint centerMap) { this.DnDMapControl.SetCenterMap(centerMap); }
//Compute the distance from AB to C //if isSegment is true, AB is a segment, not a line. private static double LineToPointDistance2D(SimplePoint linePoint1, SimplePoint linePoint2, SimplePoint pointTest, bool isSegment = true) { if (linePoint1.X == linePoint1.X && linePoint1.Y == linePoint2.Y) return 255; var pointA = new double[] { linePoint1.X, linePoint1.Y }; var pointB = new double[] { linePoint2.X, linePoint2.Y }; var pointC = new double[] { pointTest.X, pointTest.Y }; double dist = CrossProduct(pointA, pointB, pointC) / Distance(pointA, pointB); if (isSegment) { double dot1 = DotProduct(pointA, pointB, pointC); if (dot1 > 0) return Distance(pointB, pointC); double dot2 = DotProduct(pointB, pointA, pointC); if (dot2 > 0) return Distance(pointA, pointC); } return Math.Abs(dist); }
private static unsafe bool ApplyFog(Bitmap fog, int delta, params FogUpdate[] fogUpdates) { if (fog == null || fogUpdates == null || !fogUpdates.Any()) return false; var isInwards = (delta < 0); var anyComplete = false; // TODO: Look into a better way to handle multiple fog updates at the same time? foreach (var fogUpdate in fogUpdates) { var points = fogUpdate.Points; var isAddingFog = !fogUpdate.IsClearing; var pointPolygon = new List<IntPoint>(points.Select(x => new IntPoint(x.X, x.Y))); var pointPolygons = new List<List<IntPoint>>() { pointPolygon }; var offsetPolygons = Clipper.OffsetPolygons(pointPolygons, delta, JoinType.jtRound); // If our offset was simply too large to have an offset polygon, we'll change it (towards 0) // until we find one. If we never do, we'll just do direct drawing as the shape is too small for alpha fading. var retryDelta = delta; if (isInwards) { // Inwards means the delta is negative (to make the fog go inwards), so we'll add to it to get it to -1. while (offsetPolygons.Count == 0 && retryDelta != -1) { // The last iteration will end up with retryDelta set to 1, which will cause the smallest offset polygon to be generated. retryDelta = Math.Min(-1, retryDelta + DnDMapConstants.FogAlphaEffectRetryDelta); offsetPolygons = Clipper.OffsetPolygons(pointPolygons, retryDelta, JoinType.jtRound); } } // If we still don't have any offset polygon, then the size must just be too small so we'll draw it using the direct method instead. if (offsetPolygons.Count == 0) { anyComplete |= ApplyFogDirect(fog, fogUpdates); continue; } var offsetPoints = offsetPolygons[0].Select(x => new SimplePoint((int)x.X, (int)x.Y)).ToArray(); // When we're doing inwards delta, the offsetPoints shape is smaller than the points shape. // Therefore, we'll flip the variables to pretend that the user drew the smaller shape. if (isInwards) { var p = points; points = offsetPoints; offsetPoints = p; } var boundingBoxBuffered = GetBoundingBox(fog, offsetPoints, 4); var boundingBox = GetBoundingBox(fog, points, 0); var bmd = fog.LockBits(boundingBoxBuffered, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); int pixelSize = 4; Parallel.For(0, bmd.Height, (y) => { var row = (byte*)bmd.Scan0 + (y * bmd.Stride); for (var x = 0; x < bmd.Width; x++) { var offsetX = x + boundingBoxBuffered.X; var offsetY = y + boundingBoxBuffered.Y; if (isAddingFog) { // If the pixel is already opaque, then we'll skip it if (row[x * pixelSize + 3] == 255) continue; } else { // If the pixel is already transparent, then we'll hide it if (row[x * pixelSize + 3] == 0) continue; } // When going outwards, we reveal everything in the points (the actual drawn polygon) // we partially reveal anything in the offset polygons // When going inwards, we reveal anythign in the offset points (an inner polygon) // we partially reveal anything in the actual polygon // This is handled by flipping the points and offsetPoints variables above. if (IsPointInPolygon(points, offsetX, offsetY)) { row[x * pixelSize + 3] = (byte)(isAddingFog ? 255 : 0); } else if (IsPointInPolygon(offsetPoints, offsetX, offsetY)) { var testPoint = new SimplePoint(offsetX, offsetY); var dist = LineToPointDistance2D(points[0], points[1], testPoint); for (int i = 0, j = points.Length - 1; i < points.Length; j = i++) { var newDist = LineToPointDistance2D(points[j], points[i], testPoint); if (newDist < dist) dist = newDist; } var alpha = (255 - 5.5 * dist); alpha = Math.Max(Math.Floor(alpha), 0); if (isAddingFog) alpha = Math.Min(alpha + row[x * pixelSize + 3], 255); else alpha = Math.Max(row[x * pixelSize + 3] - alpha, 0); row[x * pixelSize + 3] = (byte)(alpha); } } }); fog.UnlockBits(bmd); anyComplete = true; } return anyComplete; }
private static bool IsPointInPolygon(SimplePoint[] polygon, float testx, float testy) { int nvert = polygon.Length; var vertx = polygon.Select(x => (float)(x.X)).ToArray(); var verty = polygon.Select(x => (float)(x.Y)).ToArray(); int i, j = 0; bool c = false; for (i = 0, j = nvert - 1; i < nvert; j = i++) { if (((verty[i] > testy) != (verty[j] > testy)) && (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i])) c = !c; } return c; }
private static Rectangle GetBoundingBox(Image fog, SimplePoint[] points, int buffer = 8) { if (points.Length == 0) { return new Rectangle(0, 0, 0, 0); } var left = points[0].X; var right = points[0].X; var top = points[0].Y; var bottom = points[0].Y; foreach (var point in points) { if (point.X < left) left = point.X; if (point.X > right) right = point.X; if (point.Y < top) top = point.Y; if (point.Y > bottom) bottom = point.Y; } var rect = new Rectangle(left, top, right - left, bottom - top); rect.X = Math.Max(0, rect.X - buffer); rect.Y = Math.Max(0, rect.Y - buffer); rect.Width = Math.Min(fog.Width - rect.X, rect.Width + buffer); rect.Height = Math.Min(fog.Height - rect.Y, rect.Height + buffer); return rect; }
private void ctlDnDMap_PerformCenterMap(SimplePoint centerMap) { connection.WriteCenterMap(centerMap); }
public override void SetCenterMap(SimplePoint centerMap) { base.SetCenterMap(centerMap, true); }
private void connection_OnCenterMapReceived(SimplePoint centerMap) { this.ctlDnDMap.SetCenterMap(centerMap); }