예제 #1
0
        public Segment(SegmentPoint start, SegmentPoint end)
        {
            Start = start;
            End   = end;

            start.Segment = this;
            end.Segment   = this;

            IsHorizontal = Math.Abs(start.Pos.X - end.Pos.X) > Math.Abs(start.Pos.Y - end.Pos.Y);
        }
예제 #2
0
        public Segment(SegmentPoint start, SegmentPoint end, ConvexHull convexHull)
        {
            Start      = start;
            End        = end;
            ConvexHull = convexHull;

            start.ConvexHull = convexHull;
            end.ConvexHull   = convexHull;

            IsHorizontal = Math.Abs(start.Pos.X - end.Pos.X) > Math.Abs(start.Pos.Y - end.Pos.Y);
        }
예제 #3
0
        public void SetVertices(Vector2[] points)
        {
            Debug.Assert(points.Length == 4, "Only rectangular convex hulls are supported");

            LastVertexChangeTime = (float)Timing.TotalTime;

            for (int i = 0; i < 4; i++)
            {
                vertices[i]    = new SegmentPoint(points[i], this);
                losVertices[i] = new SegmentPoint(points[i], this);
            }
            for (int i = 0; i < 4; i++)
            {
                segments[i] = new Segment(vertices[i], vertices[(i + 1) % 4], this);
            }

            int margin = 0;

            if (Math.Abs(points[0].X - points[2].X) < Math.Abs(points[0].Y - points[1].Y))
            {
                losVertices[0].Pos = new Vector2(points[0].X + margin, points[0].Y);
                losVertices[1].Pos = new Vector2(points[1].X + margin, points[1].Y);
                losVertices[2].Pos = new Vector2(points[2].X - margin, points[2].Y);
                losVertices[3].Pos = new Vector2(points[3].X - margin, points[3].Y);
            }
            else
            {
                losVertices[0].Pos = new Vector2(points[0].X, points[0].Y + margin);
                losVertices[1].Pos = new Vector2(points[1].X, points[1].Y - margin);
                losVertices[2].Pos = new Vector2(points[2].X, points[2].Y - margin);
                losVertices[3].Pos = new Vector2(points[3].X, points[3].Y + margin);
            }

            CalculateDimensions();

            if (parentEntity == null || ignoreEdge == null)
            {
                return;
            }
            for (int i = 0; i < 4; i++)
            {
                ignoreEdge[i] = false;
            }

            var chList = HullLists.Find(x => x.Submarine == parentEntity.Submarine);

            if (chList != null)
            {
                foreach (ConvexHull ch in chList.List)
                {
                    UpdateIgnoredEdges(ch);
                }
            }
        }
예제 #4
0
        public Segment(SegmentPoint start, SegmentPoint end, ConvexHull convexHull)
        {
            if (start.Pos.Y > end.Pos.Y)
            {
                var temp = start;
                start = end;
                end   = temp;
            }

            Start      = start;
            End        = end;
            ConvexHull = convexHull;

            start.ConvexHull = convexHull;
            end.ConvexHull   = convexHull;

            IsHorizontal  = Math.Abs(start.Pos.X - end.Pos.X) > Math.Abs(start.Pos.Y - end.Pos.Y);
            IsAxisAligned = Math.Abs(start.Pos.X - end.Pos.X) < 0.1f || Math.Abs(start.Pos.Y - end.Pos.Y) < 0.001f;
        }
예제 #5
0
        private List <Vector2> FindRaycastHits()
        {
            if (!CastShadows)
            {
                return(null);
            }
            if (range < 1.0f || color.A < 0.01f)
            {
                return(null);
            }

            Vector2 drawPos = position;

            if (ParentSub != null)
            {
                drawPos += ParentSub.DrawPosition;
            }

            var hulls = new List <ConvexHull>();// ConvexHull.GetHullsInRange(position, range, ParentSub);

            foreach (ConvexHullList chList in hullsInRange)
            {
                //hulls.AddRange(chList.List);
                foreach (ConvexHull hull in chList.List)
                {
                    if (!chList.IsHidden.Contains(hull))
                    {
                        hulls.Add(hull);
                    }
                    //hulls.Add(hull);
                }
                foreach (ConvexHull hull in chList.List)
                {
                    chList.IsHidden.Add(hull);
                }
            }

            float bounds = range * 2;
            //find convexhull segments that are close enough and facing towards the light source
            List <Segment>      visibleSegments = new List <Segment>();
            List <SegmentPoint> points          = new List <SegmentPoint>();

            foreach (ConvexHull hull in hulls)
            {
                hull.RefreshWorldPositions();

                var visibleHullSegments = hull.GetVisibleSegments(drawPos);
                visibleSegments.AddRange(visibleHullSegments);
            }

            //Generate new points at the intersections between segments
            //This is necessary for the light volume to generate properly on some subs
            for (int i = 0; i < visibleSegments.Count; i++)
            {
                Vector2 p1a = visibleSegments[i].Start.WorldPos;
                Vector2 p1b = visibleSegments[i].End.WorldPos;

                for (int j = 0; j < visibleSegments.Count; j++)
                {
                    if (j == i)
                    {
                        continue;
                    }
                    Vector2 p2a = visibleSegments[j].Start.WorldPos;
                    Vector2 p2b = visibleSegments[j].End.WorldPos;

                    if (Vector2.DistanceSquared(p1a, p2a) < 25.0f ||
                        Vector2.DistanceSquared(p1a, p2b) < 25.0f ||
                        Vector2.DistanceSquared(p1b, p2a) < 25.0f ||
                        Vector2.DistanceSquared(p1b, p2b) < 25.0f)
                    {
                        continue;
                    }

                    Vector2?intersection = MathUtils.GetLineIntersection(p1a, p1b, p2a, p2b);

                    if (intersection != null)
                    {
                        Vector2 intersectionVal = intersection.Value;

                        SegmentPoint start = visibleSegments[i].Start;
                        SegmentPoint end   = visibleSegments[i].End;
                        SegmentPoint mid   = new SegmentPoint(intersectionVal, null);

                        if (Vector2.DistanceSquared(start.WorldPos, mid.WorldPos) < 25.0f ||
                            Vector2.DistanceSquared(end.WorldPos, mid.WorldPos) < 25.0f)
                        {
                            continue;
                        }

                        Segment seg1 = new Segment(start, mid, visibleSegments[i].ConvexHull); seg1.IsHorizontal = visibleSegments[i].IsHorizontal;
                        Segment seg2 = new Segment(mid, end, visibleSegments[i].ConvexHull); seg2.IsHorizontal = visibleSegments[i].IsHorizontal;
                        visibleSegments[i] = seg1;
                        visibleSegments.Insert(i + 1, seg2);
                        i--;
                        break;
                    }
                }
            }

            foreach (Segment s in visibleSegments)
            {
                points.Add(s.Start);
                points.Add(s.End);
                if (Math.Abs(s.Start.WorldPos.X - drawPos.X) > bounds)
                {
                    bounds = Math.Abs(s.Start.WorldPos.X - drawPos.X);
                }
                if (Math.Abs(s.Start.WorldPos.Y - drawPos.Y) > bounds)
                {
                    bounds = Math.Abs(s.Start.WorldPos.Y - drawPos.Y);
                }
                if (Math.Abs(s.End.WorldPos.X - drawPos.X) > bounds)
                {
                    bounds = Math.Abs(s.End.WorldPos.X - drawPos.X);
                }
                if (Math.Abs(s.End.WorldPos.Y - drawPos.Y) > bounds)
                {
                    bounds = Math.Abs(s.End.WorldPos.Y - drawPos.Y);
                }
            }

            //add a square-shaped boundary to make sure we've got something to construct the triangles from
            //even if there aren't enough hull segments around the light source

            //(might be more effective to calculate if we actually need these extra points)
            var boundaryCorners = new List <SegmentPoint> {
                new SegmentPoint(new Vector2(drawPos.X + bounds, drawPos.Y + bounds), null),
                new SegmentPoint(new Vector2(drawPos.X + bounds, drawPos.Y - bounds), null),
                new SegmentPoint(new Vector2(drawPos.X - bounds, drawPos.Y - bounds), null),
                new SegmentPoint(new Vector2(drawPos.X - bounds, drawPos.Y + bounds), null)
            };

            points.AddRange(boundaryCorners);

            for (int i = 0; i < 4; i++)
            {
                visibleSegments.Add(new Segment(boundaryCorners[i], boundaryCorners[(i + 1) % 4], null));
            }

            var compareCCW = new CompareSegmentPointCW(drawPos);

            try
            {
                points.Sort(compareCCW);
            }
            catch (Exception e)
            {
                StringBuilder sb = new StringBuilder("Constructing light volumes failed! Light pos: " + drawPos + ", Hull verts:\n");
                foreach (SegmentPoint sp in points)
                {
                    sb.AppendLine(sp.Pos.ToString());
                }
                DebugConsole.ThrowError(sb.ToString(), e);
            }

            List <Vector2> output = new List <Vector2>();

            //List<Pair<int, Vector2>> preOutput = new List<Pair<int, Vector2>>();

            //remove points that are very close to each other
            for (int i = 0; i < points.Count - 1; i++)
            {
                if (Math.Abs(points[i].WorldPos.X - points[i + 1].WorldPos.X) < 6 &&
                    Math.Abs(points[i].WorldPos.Y - points[i + 1].WorldPos.Y) < 6)
                {
                    points.RemoveAt(i + 1);
                    i--;
                }
            }

            foreach (SegmentPoint p in points)
            {
                Vector2 dir       = Vector2.Normalize(p.WorldPos - drawPos);
                Vector2 dirNormal = new Vector2(-dir.Y, dir.X) * 3;

                //do two slightly offset raycasts to hit the segment itself and whatever's behind it
                Pair <int, Vector2> intersection1 = RayCast(drawPos, drawPos + dir * bounds * 2 - dirNormal, visibleSegments);
                Pair <int, Vector2> intersection2 = RayCast(drawPos, drawPos + dir * bounds * 2 + dirNormal, visibleSegments);

                if (intersection1.First < 0)
                {
                    return(new List <Vector2>());
                }
                if (intersection2.First < 0)
                {
                    return(new List <Vector2>());
                }
                Segment seg1 = visibleSegments[intersection1.First];
                Segment seg2 = visibleSegments[intersection2.First];

                bool isPoint1 = MathUtils.LineToPointDistance(seg1.Start.WorldPos, seg1.End.WorldPos, p.WorldPos) < 5.0f;
                bool isPoint2 = MathUtils.LineToPointDistance(seg2.Start.WorldPos, seg2.End.WorldPos, p.WorldPos) < 5.0f;

                if (isPoint1 && isPoint2)
                {
                    //hit at the current segmentpoint -> place the segmentpoint into the list
                    output.Add(p.WorldPos);

                    foreach (ConvexHullList hullList in hullsInRange)
                    {
                        hullList.IsHidden.Remove(p.ConvexHull);
                        hullList.IsHidden.Remove(seg1.ConvexHull);
                        hullList.IsHidden.Remove(seg2.ConvexHull);
                    }
                }
                else if (intersection1.First != intersection2.First)
                {
                    //the raycasts landed on different segments
                    //we definitely want to generate new geometry here
                    output.Add(isPoint1 ? p.WorldPos : intersection1.Second);
                    output.Add(isPoint2 ? p.WorldPos : intersection2.Second);

                    foreach (ConvexHullList hullList in hullsInRange)
                    {
                        hullList.IsHidden.Remove(p.ConvexHull);
                        hullList.IsHidden.Remove(seg1.ConvexHull);
                        hullList.IsHidden.Remove(seg2.ConvexHull);
                    }
                }
                //if neither of the conditions above are met, we just assume
                //that the raycasts both resulted on the same segment
                //and creating geometry here would be wasteful
            }

            //remove points that are very close to each other
            for (int i = 0; i < output.Count - 1; i++)
            {
                if (Math.Abs(output[i].X - output[i + 1].X) < 6 &&
                    Math.Abs(output[i].Y - output[i + 1].Y) < 6)
                {
                    output.RemoveAt(i + 1);
                    i--;
                }
            }

            return(output);
        }
예제 #6
0
        public void SetVertices(Vector2[] points, Matrix?rotationMatrix = null)
        {
            Debug.Assert(points.Length == 4, "Only rectangular convex hulls are supported");

            LastVertexChangeTime = (float)Timing.TotalTime;

            for (int i = 0; i < 4; i++)
            {
                vertices[i]    = new SegmentPoint(points[i], this);
                losVertices[i] = new SegmentPoint(points[i], this);
                losOffsets[i]  = null;
            }

            for (int i = 0; i < 4; i++)
            {
                ignoreEdge[i] = false;
            }

            overlappingHulls.Clear();

            int margin = 0;

            if (Math.Abs(points[0].X - points[2].X) < Math.Abs(points[0].Y - points[2].Y))
            {
                losVertices[0].Pos = new Vector2(points[0].X + margin, points[0].Y);
                losVertices[1].Pos = new Vector2(points[1].X + margin, points[1].Y);
                losVertices[2].Pos = new Vector2(points[2].X - margin, points[2].Y);
                losVertices[3].Pos = new Vector2(points[3].X - margin, points[3].Y);
            }
            else
            {
                losVertices[0].Pos = new Vector2(points[0].X, points[0].Y + margin);
                losVertices[1].Pos = new Vector2(points[1].X, points[1].Y - margin);
                losVertices[2].Pos = new Vector2(points[2].X, points[2].Y - margin);
                losVertices[3].Pos = new Vector2(points[3].X, points[3].Y + margin);
            }

            if (rotationMatrix.HasValue)
            {
                for (int i = 0; i < vertices.Length; i++)
                {
                    vertices[i].Pos    = Vector2.Transform(vertices[i].Pos, rotationMatrix.Value);
                    losVertices[i].Pos = Vector2.Transform(losVertices[i].Pos, rotationMatrix.Value);
                }
            }
            for (int i = 0; i < 4; i++)
            {
                segments[i] = new Segment(vertices[i], vertices[(i + 1) % 4], this);
            }

            CalculateDimensions();

            if (ParentEntity == null)
            {
                return;
            }

            var chList = HullLists.Find(h => h.Submarine == ParentEntity.Submarine);

            if (chList != null)
            {
                overlappingHulls.Clear();
                foreach (ConvexHull ch in chList.List)
                {
                    MergeOverlappingSegments(ch);
                }
            }
        }