/// <summary>
        ///
        /// </summary>
        /// <param name="RooFile"></param>
        public override void ResolveIndices(RooFile RooFile)
        {
            // indices properties are not zero-based, but the arrays/lists are

            // get reference to parent wall
            if (WallReference > 0 &&
                RooFile.Walls.Count > WallReference - 1)
            {
                Wall = RooFile.Walls[WallReference - 1];
            }

            // get right tree child
            if (Right > 0 &&
                RooFile.BSPTree.Count > Right - 1)
            {
                RightChild = RooFile.BSPTree[Right - 1];
            }

            // get left tree child
            if (Left > 0 &&
                RooFile.BSPTree.Count > Left - 1)
            {
                LeftChild = RooFile.BSPTree[Left - 1];
            }
        }
        public static void Build(RooFile Room)
        {
            if (Room == null)
            {
                return;
            }

            room = Room;

            if (BuildStarted != null)
            {
                BuildStarted(null, new EventArgs());
            }

            ///////////////////////////////////////////////////////////////

            BoundingBox2D box = Room.GetBoundingBox2D(true);

            Polygon poly = new Polygon();

            poly.Add(box.Min);
            poly.Add(box.Min + new V2(box.Max.X - box.Min.X, 0f));
            poly.Add(box.Max);
            poly.Add(box.Max - new V2(box.Max.X - box.Min.X, 0f));

            ///////////////////////////////////////////////////////////////

            // clean up old data from room
            Room.Walls.Clear();
            Room.BSPTree.Clear();
            foreach (RooSector sector in Room.Sectors)
            {
                sector.Walls.Clear();
                sector.Sides.Clear();
            }

            // convert roomeditor walls to roowall
            for (int i = 0; i < Room.WallsEditor.Count; i++)
            {
                RooWall wall = Room.WallsEditor[i].ToRooWall(RooFile.VERSIONHIGHRESGRID, Room);
                Room.Walls.Add(wall);
            }

            ///////////////////////////////////////////////////////////////

            RooBSPItem tree = BuildNode(Room.Walls, poly, 0);

            ///////////////////////////////////////////////////////////////

            FillNode(tree, Room.BSPTree);
            SetNums(Room.BSPTree);
        }
        private static void FillNode(RooBSPItem Node, List <RooBSPItem> NodeList)
        {
            if (Node == null)
            {
                return;
            }

            NodeList.Add(Node);

            if (Node.Type == RooBSPItem.NodeType.Node)
            {
                RooPartitionLine node = (RooPartitionLine)Node;

                FillNode(node.RightChild, NodeList);
                FillNode(node.LeftChild, NodeList);
            }
        }
示例#4
0
        private static void FillNode(RooBSPItem Node, List<RooBSPItem> NodeList)
        {
            if (Node == null)
                return;

            NodeList.Add(Node);
            
            if (Node.Type == RooBSPItem.NodeType.Node)
            {
                RooPartitionLine node = (RooPartitionLine)Node;

                FillNode(node.RightChild, NodeList);
                FillNode(node.LeftChild, NodeList);
            }
        }
        /// <summary>
        /// Collisions with wall segments for user movements using the BSP tree.
        /// Therefore with logarithmic rather than linear costs.
        /// </summary>
        /// <remarks>
        /// The algorithm goes like this (starts at root)
        /// (1) Get the sides of both endpoints (start, end) using the splitter (node)
        /// (2) If both endpoints are on the same side, there is no collision with any wall in the splitter
        ///     and only one of the two subtrees must be visited then.
        /// (3) If there is an intersection with the infinite splitter, check the finite wall segments
        ///     in the splitter for intersection. If none found, split up the vector (start, end) at the intersection
        ///     and recusively start again for both subtrees using the just created two chunks of start vector.
        /// </remarks>
        /// <param name="Node"></param>
        /// <param name="Start"></param>
        /// <param name="End"></param>
        /// <param name="PlayerHeight"></param>
        /// <returns></returns>
        protected RooWall VerifyMoveTree(RooBSPItem Node, V3 Start, V2 End, Real PlayerHeight)
        {
            if (Node == null || Node.Type != RooBSPItem.NodeType.Node)
                return null;

            /*************************************************************/

            RooPartitionLine line = (RooPartitionLine)Node;

            int side1 = Math.Sign(line.A * Start.X + line.B * Start.Z + line.C);
            int side2 = Math.Sign(line.A * End.X + line.B * End.Y + line.C);

            /*************************************************************/

            // both endpoints on the same side of splitter -> no intersection
            // climb down only one of the two subtrees of the node
            if (side1 == side2 && side1 != 0)
            {
                // left
                if (side1 < 0)
                    return VerifyMoveTree(line.LeftChild, Start, End, PlayerHeight);

                // right
                else
                    return VerifyMoveTree(line.RightChild, Start, End, PlayerHeight);
            }

            /*************************************************************/

            // endpoints are on different sides or both on infinite line
            else
            {
                RooWall wall = line.Wall;
                V2 intersect;
                V2 start2D = new V2(Start.X, Start.Z);

                if (wall == null)
                    return null;

                /*************************************************************/

                // intersect with infinite splitter
                LineInfiniteLineIntersectionType typ =
                    MathUtil.IntersectLineInfiniteLine(start2D, End, wall.P1, wall.P2, out intersect);

                /*************************************************************/

                // see if intersection with infinite splitter is on a wall segment in plane
                while (wall != null)
                {
                    if (wall.IsBlocking(Start, End, PlayerHeight))
                        return wall;

                    // loop over next wall in same plane
                    wall = wall.NextWallInPlane;
                }

                /*************************************************************/

                // no finite wallsegment in splitter plane intersects:
                // if vector is fully in splitter, we're done
                if (side1 == 0 && side2 == 0)
                    return null;

                // otherwise split up the vector in left and right half
                // and possible check both
                else if (side1 < 0 && side2 > 0)
                {
                    RooWall wl = VerifyMoveTree(line.LeftChild, Start, intersect, PlayerHeight);

                    if (wl != null)
                        return wl;

                    else
                        return VerifyMoveTree(line.RightChild, new V3(intersect.X, Start.Y, intersect.Y), End, PlayerHeight);
                }
                else
                {
                    RooWall wl = VerifyMoveTree(line.RightChild, Start, intersect, PlayerHeight);

                    if (wl != null)
                        return wl;

                    else
                        return VerifyMoveTree(line.LeftChild, new V3(intersect.X, Start.Y, intersect.Y), End, PlayerHeight);
                }
            }
        }
        /// <summary>
        /// Recursively walks the BSP tree start at given node,
        /// to find the subsector (leaf) containing the point.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        protected RooBSPItem GetSubSectorAt(RooBSPItem node, Real x, Real y)
        {
            if (node == null)
                return null;

            int side;

            if (node.Type == RooBSPItem.NodeType.Leaf)
                return node;
            else
            {
                RooPartitionLine line = (RooPartitionLine)node;
                side = Math.Sign(line.A * x + line.B * y + line.C);

                if (side == 0)
                {
                    if (line.RightChild != null)
                    {
                        return GetSubSectorAt(line.RightChild, x, y);
                    }
                    else
                    {
                        return GetSubSectorAt(line.LeftChild, x, y);
                    }
                }
                else if (side > 0)
                {
                    return GetSubSectorAt(line.RightChild, x, y);
                }
                else
                {
                    return GetSubSectorAt(line.LeftChild, x, y);
                }
            }
        }
示例#7
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="Node"></param>
        /// <param name="Start"></param>
        /// <param name="End"></param>
        /// <returns>True if OK, false if collision.</returns>
        protected bool VerifySightByTree(RooBSPItem Node, V3 Start, V3 End)
        {
            if (Node == null || Node.Type != RooBSPItem.NodeType.Node)
                return true;

            /*************************************************************/

            RooPartitionLine line = (RooPartitionLine)Node;
            RooWall wall = line.Wall;
            V2 start2D = new V2(Start.X, Start.Z);
            V2 end2D = new V2(End.X, End.Z);

            /*************************************************************/

            Real startDist  = line.GetDistance(start2D);
            Real endDist    = line.GetDistance(end2D);

            /*************************************************************/

            // both endpoints on negative side
            if (startDist < 0.0f && endDist < 0.0f)
                return VerifySightByTree(line.LeftChild, Start, End);

            // both endpoints on positive side
            else if (startDist > 0.0f && endDist > 0.0f)
                return VerifySightByTree(line.RightChild, Start, End);

            // crosses infinite splitter or one or both points on splitter
            else
            {
                // test walls of splitter
                while (wall != null)
                {
                    if (wall.IsBlockingSight(Start, End))
                        return false;

                    // loop over next wall in same plane
                    wall = wall.NextWallInPlane;
                }

                // must climb down both subtrees, go left first
                bool wl = VerifySightByTree(line.LeftChild, Start, End);

                // return collision if already found
                if (wl == false)
                    return wl;

                // try other subtree otherwise
                else
                    return VerifySightByTree(line.RightChild, Start, End);
            }           
        }
示例#8
0
        /// <summary>
        /// Collisions with wall segments for user movements using the BSP tree.
        /// Therefore with logarithmic rather than linear costs.
        /// </summary>
        /// <param name="Node"></param>
        /// <param name="Start"></param>
        /// <param name="End"></param>
        /// <param name="PlayerHeight"></param>
        /// <param name="IgnoreWall"></param>
        /// <returns></returns>
        protected RooWall VerifyMoveByTree(RooBSPItem Node, V3 Start, V2 End, Real PlayerHeight, RooWall IgnoreWall = null)
        {
            if (Node == null || Node.Type != RooBSPItem.NodeType.Node)
                return null;

            /*************************************************************/

            RooPartitionLine line = (RooPartitionLine)Node;
            RooWall wall = line.Wall;
            V2 start2D = new V2(Start.X, Start.Z);

            /*************************************************************/
            
            // check node boundingbox
            if (!line.BoundingBox.IsInside(End, GeometryConstants.WALLMINDISTANCE) && 
                !line.BoundingBox.IsInside(start2D, GeometryConstants.WALLMINDISTANCE))
                return null;
       
            /*************************************************************/

            // test walls of splitter
            while (wall != null)
            {
                if (wall != IgnoreWall && wall.IsBlockingMove(Start, End, PlayerHeight))
                    return wall;

                // loop over next wall in same plane
                wall = wall.NextWallInPlane;
            }

            /*************************************************************/

            RooWall wl = VerifyMoveByTree(line.LeftChild, Start, End, PlayerHeight, IgnoreWall);

            if (wl != null)
                return wl;

            else
                return VerifyMoveByTree(line.RightChild, Start, End, PlayerHeight, IgnoreWall);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="RooFile"></param>
        public override void ResolveIndices(RooFile RooFile)
        {
            // indices properties are not zero-based, but the arrays/lists are

            // get reference to parent wall
            if (WallReference > 0 &&
                RooFile.Walls.Count > WallReference - 1)
            {
                Wall = RooFile.Walls[WallReference - 1];
            }

            // get right tree child
            if (Right > 0 &&
                RooFile.BSPTree.Count > Right - 1)
            {
                RightChild = RooFile.BSPTree[Right - 1];
            }

            // get left tree child
            if (Left > 0 &&
                RooFile.BSPTree.Count > Left - 1)
            {
                LeftChild = RooFile.BSPTree[Left - 1];
            }
        }