public BSPTreeNode GetLeafNode(Vector3i index) { BSPTreeNode n = node; Vector3i cells = GetCellCount(); for (int i = 0; i < 3; i++) { int min = 0; int max = cells[i]; while (max - 1 > min) { int mid = (max + min) / 2; string s; if (index[i] > mid) { n = n.right; min = mid; } else { n = n.left; max = mid; } } } // Debug.Log("cells " + cells); return(n); }
public void Insert(Triangle3D t, T val) { if (node == null) { node = new BSPTreeNode(t, val); } else { node.Insert(t, val); } }
public void Insert(Plane3D p) { if (node == null) { node = new BSPTreeNode(p); } else { node.Insert(p); } }
public void DebugQuadPlanes(String s, BSPTreeNode n) { if (n == null || (n.triangles.Count > 0)) { // Debug.Log("Tree "+s+" "+(n==null?-1:n.ToList().Count)); } else { DebugQuadPlanes(s + n.plane.normal + n.plane.distance + "L", n.left); DebugQuadPlanes(s + n.plane.normal + n.plane.distance + "R", n.right); } }
// split both child spaces public void Insert(Plane3D p) { if (this.plane.normal == p.normal) { Vector3D point = p.normal * -p.distance; double distanceToPoint = this.plane.GetDistanceToPoint(point); if (distanceToPoint > 0) { if (left == null) { left = new BSPTreeNode(p); } else { left.Insert(p); } } else if (distanceToPoint < 0) { if (right == null) { right = new BSPTreeNode(p); } else { right.Insert(p); } } else { Debug.LogError("Splitting plane already defined"); } } else { if (left == null) { left = new BSPTreeNode(p); } else { left.Insert(p); } if (right == null) { right = new BSPTreeNode(p); } else { right.Insert(p); } } }
public static object Serialize_BSPTreeNode(object _obj, System.Type type, OverloadLevelConvertSerializer serializer) { BSPTreeNode obj = (BSPTreeNode)_obj; if (serializer.IsWriting) { serializer.SerializeOut_vector4(obj.PlaneEq); serializer.SerializeOut_int32(obj.BackNodeIndex); serializer.SerializeOut_int32(obj.FrontNodeIndex); } else { obj.PlaneEq = serializer.SerializeIn_vector4(); obj.BackNodeIndex = serializer.SerializeIn_int32(); obj.FrontNodeIndex = serializer.SerializeIn_int32(); } return(obj); }
void SplitNode(BSPTreeNode node, BSPSplitDirection splitDir, float splitRange, int recursionLevel, List <BSPTreeNode> leafNodes) { // Split a node so that we get a new range [min_x,min_y,max_x,max_y] so that a room can be created with these bounds // Note that these are bounds on the indices of the virtual map and that they are left-inclusive! //Debug.Log("LEVEL " + recursionLevel + " [" + node.areaBounds.min_x + "," + node.areaBounds.max_x + "] [" + node.areaBounds.min_y + "," + node.areaBounds.max_y + "]"); if (recursionLevel == 0) { leafNodes.Add(node); return; } int splitPoint; // Pick a random coordinate on that direction splitPoint = GetSplitPoint(node.areaBounds, splitDir, splitRange); node.splitDirection = splitDir; //Debug.Log("ON " + splitDir + " CHOSEN SPLIT: " + splitPoint); // Create child nodes from that split point switch (splitDir) { case BSPSplitDirection.VERTICAL: node.left = new BSPTreeNode(node.areaBounds.min_x, node.areaBounds.min_y, splitPoint, node.areaBounds.max_y); node.right = new BSPTreeNode(splitPoint, node.areaBounds.min_y, node.areaBounds.max_x, node.areaBounds.max_y); break; case BSPSplitDirection.HORIZONTAL: node.left = new BSPTreeNode(node.areaBounds.min_x, node.areaBounds.min_y, node.areaBounds.max_x, splitPoint); node.right = new BSPTreeNode(node.areaBounds.min_x, splitPoint, node.areaBounds.max_x, node.areaBounds.max_y); break; } // Next pass: go through child nodes recursionLevel--; splitDir = (BSPSplitDirection)Mathf.Repeat((int)(splitDir + 1), (int)BSPSplitDirection.MAX); SplitNode(node.left, splitDir, splitRange, recursionLevel, leafNodes); SplitNode(node.right, splitDir, splitRange, recursionLevel, leafNodes); }
void LinkCorridors(BSPTreeNode node, VirtualMap map, int recursionLevel, bool isLeft = false) { //Debug.Log("Linking at level " + recursionLevel); // We link corridors recursively if (node.left != null && node.right != null) { // First we recurse to the children LinkCorridors(node.left, map, recursionLevel + 1, isLeft: true); LinkCorridors(node.right, map, recursionLevel + 1, isLeft: false); // We get the left, we get the right, and we link them // We do this for non-leaf nodes if (node.left.roomBounds != null && node.right.roomBounds != null) { // DEBUG: Only connect at higher recursion level if (recursionLevel >= 0) { if (node.splitDirection == BSPSplitDirection.HORIZONTAL) { CreateVerticalCorridor(map, node.left.roomBounds, node.right.roomBounds); } else { CreateHorizontalCorridor(map, node.left.roomBounds, node.right.roomBounds); } } //if (isLeft) //return; //return; // Now that we linked the children, we update the bounds of this node, which had no roomBounds before BSPTreeNodeBounds lb = node.left.roomBounds; BSPTreeNodeBounds rb = node.right.roomBounds; // We always get the more central one, to make sure we can connect easily // Central one: has midpoint closest to the middle of the map int mid_x_map = map.ActualWidth / 2; int mid_y_map = map.ActualHeight / 2; int mid_x_lb = (lb.min_x + lb.max_x) / 2; int mid_y_lb = (lb.min_y + lb.max_y) / 2; int mid_x_rb = (rb.min_x + rb.max_x) / 2; int mid_y_rb = (rb.min_y + rb.max_y) / 2; //Debug.Log("MID_MAP " + mid_x_map); //Debug.Log("mid_x_lb " + mid_x_lb); //Debug.Log("mid_x_rb " + mid_x_rb); // Check the more central one int dist_lb = Mathf.Abs(mid_x_lb - mid_x_map) + Mathf.Abs(mid_y_lb - mid_y_map); int dist_rb = Mathf.Abs(mid_x_rb - mid_x_map) + Mathf.Abs(mid_y_rb - mid_y_map); //Debug.Log("RECURSION " + recursionLevel); //Debug.Log("THIS: " + node.areaBounds);// + " CONNECTED INSIDE: " + node.roomBounds); //Debug.Log("Distance of L is " + dist_lb + " L: " + lb); //Debug.Log("Distance of R is " + dist_rb + " R: " + rb); //Debug.Log("CLOSEST L? " + (dist_lb <= dist_rb)); if (dist_lb <= dist_rb) { node.roomBounds = new BSPTreeNodeBounds(lb.min_x, lb.min_y, lb.max_x, lb.max_y); } else { node.roomBounds = new BSPTreeNodeBounds(rb.min_x, rb.min_y, rb.max_x, rb.max_y); } // We use all the range (WRONG! may not connect!) /* * node.roomBounds = new BSPTreeNodeBounds(Mathf.Min(lb.min_x, rb.min_x), * Mathf.Min(lb.min_y, rb.min_y), * Mathf.Max(lb.max_x, rb.max_x), * Mathf.Max(lb.max_y, rb.max_y) * );*/ // We connect left or right, depending on where we are (WRONG) /* * if (!isLeft) * { * node.roomBounds = new BSPTreeNodeBounds(lb.min_x, lb.min_y, lb.max_x, lb.max_y); * } * else * { * node.roomBounds = new BSPTreeNodeBounds(rb.min_x, rb.min_y, rb.max_x, rb.max_y); * }*/ //node.roomBounds = new BSPTreeNodeBounds(lb.min_x, lb.min_y, lb.max_x, lb.max_y); } } }
VirtualRoom CreateRoom(VirtualMap map, RoomGenerator roomGenerator, BSPTreeNode node, CellLocation starting_location) { // Get the maximum bounds BSPTreeNodeBounds bounds = node.areaBounds; int range_x = bounds.max_x - bounds.min_x; int range_y = bounds.max_y - bounds.min_y; // Cannot create a room if the area is empty! if (range_x == 0 || range_y == 0) { Debug.LogWarning("Room size too small to be created! " + range_x + "," + range_y); return(null); } // Choose a random size for the room int min_size_x = Mathf.Max(1, Mathf.FloorToInt(range_x * roomSizeMinRange)); int max_size_x = Mathf.Max(1, Mathf.CeilToInt(range_x * roomSizeMaxRange)); int min_size_y = Mathf.Max(1, Mathf.FloorToInt(range_y * roomSizeMinRange)); int max_size_y = Mathf.Max(1, Mathf.CeilToInt(range_y * roomSizeMaxRange)); // Compute size int size_x = DungeonGenerator.Random.Instance.Next(min_size_x, max_size_x); int size_y = DungeonGenerator.Random.Instance.Next(min_size_y, max_size_y); // Compute start int start_x, start_y; start_x = bounds.min_x + DungeonGenerator.Random.Instance.Next(range_x - size_x); start_y = bounds.min_y + DungeonGenerator.Random.Instance.Next(range_y - size_y); // If the starting location is inside these bounds, we must force it to create the room on it if (starting_location.isValid() && bounds.Contain(starting_location)) { //Debug.Log("YES IN"); int x = starting_location.x / 2; int y = starting_location.y / 2; //Debug.Log("Start bounds: " + (new BSPTreeNodeBounds(start_x, start_y, start_x + size_x, start_y + size_y)).ToString()); // Make sure the start includes this, or decrease it if (x < start_x) { start_x = x; } if (y < start_y) { start_y = y; } //Debug.Log(y); //Debug.Log(start_y + size_y); // Make sure the end includes thid, or increase it if (x + 1 >= start_x + size_x) { size_x = x + 1 - start_x; } if (y + 1 >= start_y + size_y) { size_y = y + 1 - start_y; } //Debug.Log("End bounds: " + (new BSPTreeNodeBounds(start_x, start_y, start_x + size_x, start_y + size_y)).ToString()); } //Debug.Log("MIN " + min_size_x + " MAX " + max_size_x + " SIZE " + size_x); //Debug.Log("SPACE " + " [" + node.areaBounds.min_x + "," + node.areaBounds.max_x + "] [" + node.areaBounds.min_y + "," + node.areaBounds.max_y + "]"); //Debug.Log("delta_low " + delta_low + " delta_high " + delta_high); //Debug.Log("CREATING ROOM: " + start_x + " + " + size_x + " || " + start_y + " + " + size_y); node.roomBounds = new BSPTreeNodeBounds(start_x, start_y, start_x + size_x, start_y + size_y); // Start and end must be converted to whole-map sizes (not just floors) start_x = start_x * 2 + 1; start_y = start_y * 2 + 1; return(roomGenerator.CreateRoom(map, size_x, size_y, start_x, start_y)); }
//----------------------------------------------------------------------------- static public World FromWorldcraftMap(WorldcraftMap wm) { // create new world World world = new World(); world.Textures = wm.Textures; world.SkyBox = new SkyBox("redSky"); world.FileName = Path.Combine(ExoEngine.sWorldPath, Path.ChangeExtension(Path.GetFileName(wm.FileName), ExoEngine.sWorldExtension)); world.Dirty = true; // find the starting location WorldcraftObject woStartPosition = wm.Objects.FindByClassName("StartPosition"); if (woStartPosition == null) { return(null); } Vector3D ptStartPosition; FaceUtils.GetMidPoint(woStartPosition.Faces, out ptStartPosition); world.StartPosition = ptStartPosition; world.StartOrientation = woStartPosition.GetPropertyInteger("orientation", 0); // find the main light WorldcraftObject woLight = wm.Objects.FindByClassName("Light"); if (woLight == null) { return(null); } Vector3D ptLight; FaceUtils.GetMidPoint(woLight.Faces, out ptLight); world.Light = ptLight; // find "Default" group... it is the static world WorldcraftObject woDefault = wm.Objects.FindByClassName("Default"); if (woDefault == null) { return(null); } // setup BSP tree Faces faces = new Faces(); // handle the other objects foreach (WorldcraftObject wo in wm.Objects) { if (wo.ClassName == "Water") { Vector3D ptMin, ptMax; FaceUtils.GetExtents(wo.Faces, out ptMin, out ptMax); Water water = new Water(ptMin, ptMax, wo.GetPropertyFloat("waveHeight", 100)); water.Color = wo.GetPropertyColor("color", Color.Azure); world.Entities.Add(water); } else if (wo.ClassName == "Duck") { Vector3D ptMin, ptMax; FaceUtils.GetExtents(wo.Faces, out ptMin, out ptMax); Duck duck = new Duck(ptMin, ptMax); duck.LoadDataSet(Path.Combine(ExoEngine.sSpritePath, "duck.odf"), wo.GetPropertyColor("color", Color.Yellow)); world.Entities.Add(duck); foreach (Face face in wo.Faces) { face.Visible = false; } faces.AddRange(wo.Faces); } } world.Entities.SortByPriority(); faces.AddRange(woDefault.Faces); FaceUtils.OptimizeFaces(faces); world.BSPTreeRoot = BSPTreeNode.FromFaces(faces); return(world); }
public void Insert(Triangle3D newTriangle, T val) { var intersection = Intersect(newTriangle); if (intersection == IntersectionResult.InPlane) { triangles.Add(new BSPTriangle(newTriangle, val)); } else if (intersection == IntersectionResult.Larger) { if (left == null) { left = new BSPTreeNode(newTriangle, val); } else { left.Insert(newTriangle, val); } } else if (intersection == IntersectionResult.Smaller) { if (right == null) { right = new BSPTreeNode(newTriangle, val); } else { right.Insert(newTriangle, val); } } else if (intersection == IntersectionResult.Intersection) { Triangle3D[] res; Split(newTriangle, out res); foreach (var l in res) { double dist = plane.GetDistanceToPoint(l.ComputeCenter()); if (dist > 0) { if (left == null) { left = new BSPTreeNode(l, val); } else { left.Insert(l, val); } } else { if (right == null) { right = new BSPTreeNode(l, val); } else { right.Insert(l, val); } } } } }