private void NavCellsFromXML(XmlNode navMeshXml) { string[] navMeshStringRows = navMeshXml.InnerText.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); uint rowCount = (uint)navMeshStringRows.Length; uint colomnCount = (uint)navMeshStringRows[0].Length; // Compute derived room properties float roomWidth = (float)colomnCount * GameConstants.NAV_MESH_WORLD_UNITS_SIZE; float roomHeight = (float)rowCount * GameConstants.NAV_MESH_WORLD_UNITS_SIZE; BitArray navCellData = new BitArray((int)(rowCount * colomnCount)); int navMeshDataIndex = 0; foreach (string rowString in navMeshStringRows) { foreach (char c in rowString) { navCellData[navMeshDataIndex] = (c == '1'); ++navMeshDataIndex; } } m_colomnCount = colomnCount; m_rowCount = rowCount; m_nonEmptyNavCellCount = 0; m_roomKey = null; m_boundingBox = new AABB3d(); m_boundingBox.SetBounds2d(-roomWidth / 2.0f, -roomHeight / 2.0f, roomWidth / 2.0f, roomHeight / 2.0f); NavMesh.BuildNavCellConnectivityGrid( colomnCount, rowCount, navCellData, out m_navCells, out m_nonEmptyNavCellCount); }
public List <IAABB> QueryOverlaps(IAABB obj) { List <IAABB> overlaps = new List <IAABB>(); Stack <int> stack = new Stack <int>(); AABB3d testAabb = obj.GetAABBBounds(); stack.Push(m_rootNodeIndex); while (stack.Count != 0) { int nodeIndex = stack.Pop(); if (nodeIndex == NullIndex) { continue; } AABBTreeNode node = m_nodes[nodeIndex]; if (node.m_bounds.Overlaps(testAabb)) { if (node.IsLeaf() && node.m_object != obj) { overlaps.Insert(0, node.m_object); } else { stack.Push(node.m_leftNodeIndex); stack.Push(node.m_rightNodeIndex); } } } return(overlaps); }
public static List <Model3d> Query(OctreeNode node, AABB3d aabb) { //std::vector<Model*> result; List <Model3d> result = new List <Model3d>(); if (IntersectionTest3D.AABB3dWithAABB3d(aabb, node.m_bounds)) { if (node.m_children == null) { for (int i = 0, size = node.m_models.Count; i < size; ++i) { OBB3d bounds = node.m_models[i].GetOBB(); if (IntersectionTest3D.AABB3dWithOBB3d(aabb, bounds)) { result.Add(node.m_models[i]); } } } else { for (int i = 0; i < 8; ++i) { List <Model3d> child = Query(node.m_children[i], aabb); if (child.Count > 0) { //result.insert(result.end(), child.begin(), child.end()); result.AddRange(child); } } } } return(result); }
public EnergyTankData() { energy_tank_id = -1; energy = 0; ownership = GameConstants.eFaction.neutral; position = new Point3d(); boundingBox = new AABB3d(); room_key = new RoomKey(); }
public NavMesh() { m_roomKey = null; m_boundingBox = new AABB3d(); m_rowCount = 0; m_colomnCount = 0; m_nonEmptyNavCellCount = 0; m_navCells = null; m_pvs = null; }
public AABB3d Merge(AABB3d other) { Vector3L selfMin = GetMin(); Vector3L otherMin = other.GetMin(); Vector3L selfMax = GetMax(); Vector3L otherMax = GetMax(); Vector3L totalMin = new Vector3L(FixPointMath.Min(selfMin.x, otherMin.x), FixPointMath.Min(selfMin.y, otherMin.y), FixPointMath.Min(selfMin.z, otherMin.z)); Vector3L totalMax = new Vector3L(FixPointMath.Max(selfMax.x, otherMax.x), FixPointMath.Max(selfMax.y, otherMax.y), FixPointMath.Max(selfMax.z, otherMax.z)); return(new AABB3d((totalMin + totalMax) / 2, totalMax - totalMin)); }
public static Vector3L ClosestPointOfPoint3dWithAABB3d(Vector3L point, AABB3d aabb) { Vector3L result = point; Vector3L min = aabb.GetMin(); Vector3L max = aabb.GetMax(); result.x = (result.x < min.x) ? min.x : result.x; result.y = (result.y < min.x) ? min.y : result.y; result.z = (result.z < min.x) ? min.z : result.z; result.x = (result.x > max.x) ? max.x : result.x; result.y = (result.y > max.x) ? max.y : result.y; result.z = (result.z > max.x) ? max.z : result.z; return(result); }
public NavMesh(RoomKey roomKey, NavMesh navMeshTemplate) { m_roomKey = new RoomKey(roomKey); m_boundingBox = new AABB3d(navMeshTemplate.m_boundingBox); m_rowCount = navMeshTemplate.m_rowCount; m_colomnCount = navMeshTemplate.m_colomnCount; m_nonEmptyNavCellCount = navMeshTemplate.m_nonEmptyNavCellCount; m_navCells = new NavCell[navMeshTemplate.m_navCells.Length]; Array.Copy(navMeshTemplate.m_navCells, m_navCells, m_navCells.Length); m_pvs = new PotentiallyVisibleSet(navMeshTemplate.m_pvs); }
public bool Contains(AABB3d other) { Vector3L selfMin = GetMin(); Vector3L otherMin = other.GetMin(); Vector3L selfMax = GetMax(); Vector3L otherMax = GetMax(); return(otherMin.x >= selfMin.x && otherMax.x <= selfMax.x && otherMin.y >= selfMin.y && otherMax.y <= selfMax.y && otherMin.z >= selfMin.z && otherMax.z <= selfMax.z); }
public bool Overlaps(AABB3d other) { Vector3L selfMin = GetMin(); Vector3L otherMin = other.GetMin(); Vector3L selfMax = GetMax(); Vector3L otherMax = GetMax(); // y is deliberately first in the list of checks below as it is seen as more likely than things // collide on x,z but not on y than they do on y thus we drop out sooner on a y fail return(selfMax.x > otherMin.x && selfMin.x < otherMax.x && selfMax.y > otherMin.y && selfMin.y < otherMax.y && selfMax.z > otherMin.z && selfMin.z < otherMax.z); }
void UpdateLeaf(int leafNodeIndex, AABB3d newAABB) { AABBTreeNode node = m_nodes[leafNodeIndex]; // if the node contains the new aabb then we just leave things // TODO: when we add velocity this check should kick in as often an update will lie within the velocity fattened initial aabb // to support this we might need to differentiate between velocity fattened aabb and actual aabb if (node.m_bounds.Contains(newAABB)) { return; } RemoveLeaf(leafNodeIndex); node.m_bounds = newAABB; InsertLeaf(leafNodeIndex); }
public void SetContent(Mesh3d mesh) { m_mesh3d = mesh; Vector3L[] vertices = mesh.GetVertices(); Vector3L min = vertices[0]; Vector3L max = vertices[0]; for (int i = 1; i < mesh.m_triangleList.Count * 3; ++i) { min.x = FixPointMath.Min(vertices[i].x, min.x); min.y = FixPointMath.Min(vertices[i].y, min.y); min.z = FixPointMath.Min(vertices[i].z, min.z); max.x = FixPointMath.Max(vertices[i].x, max.x); max.y = FixPointMath.Max(vertices[i].y, max.y); max.z = FixPointMath.Max(vertices[i].z, max.z); } m_aabb = Mesh3d.FromMinMax(min, max); }
public List <Model3d> Query(AABB3d aabb) { if (m_octree != null) { // :: lets the compiler know to look outside class scope return(Octree3d.Query(m_octree, aabb)); } List <Model3d> result = new List <Model3d>(); for (int i = 0, size = m_modleList.Count; i < size; ++i) { OBB3d bounds = m_modleList[i].GetOBB(); if (IntersectionTest3D.AABB3dWithOBB3d(aabb, bounds)) { result.Add(m_modleList[i]); } } return(result); }
private void NavCellsFromCompressedRawByteArray( byte[] compressedNavCells) { byte[] header = new byte[COMPRESSED_DATA_HEADER_BYTE_COUNT]; byte[] uncompressed = CompressionUtilities.RunLengthDecodeByteArray( compressedNavCells, CompressionUtilities.eEncodeType.Zeros, header); BitArray navCellData = new BitArray(uncompressed); // Read out the header Debug.Assert(COMPRESSED_DATA_HEADER_BYTE_COUNT == 2); uint colomnCount = (uint)header[0]; uint rowCount = (uint)header[1]; // Compute derived room properties int navCellCount = (int)(rowCount * colomnCount); float roomWidth = (float)colomnCount * GameConstants.NAV_MESH_WORLD_UNITS_SIZE; float roomHeight = (float)rowCount * GameConstants.NAV_MESH_WORLD_UNITS_SIZE; // Initialize the nav cell derived data m_colomnCount = colomnCount; m_rowCount = rowCount; m_nonEmptyNavCellCount = 0; m_roomKey = null; m_boundingBox = new AABB3d(); m_boundingBox.SetBounds2d(-roomWidth / 2.0f, -roomHeight / 2.0f, roomWidth / 2.0f, roomHeight / 2.0f); // Truncate extra bits added due to the bit array getting rounded up to the nearest byte navCellData.Length = navCellCount; // Compute the connectivity data from the nav cell bit array NavMesh.BuildNavCellConnectivityGrid( colomnCount, rowCount, navCellData, out m_navCells, out m_nonEmptyNavCellCount); }
public void AppendAABB(AABB3d aabb) { Point3d p0 = aabb.Min; Point3d p1 = aabb.Max; int start = vertices.Count + 1; // Vertex indices are 1-based, not 0-based vertices.Add(new Point3d(p0.x, p0.y, p0.z)); // 0 vertices.Add(new Point3d(p1.x, p0.y, p0.z)); // 1 vertices.Add(new Point3d(p1.x, p1.y, p0.z)); // 2 vertices.Add(new Point3d(p0.x, p1.y, p0.z)); // 3 vertices.Add(new Point3d(p0.x, p0.y, p1.z)); // 4 vertices.Add(new Point3d(p1.x, p0.y, p1.z)); // 5 vertices.Add(new Point3d(p1.x, p1.y, p1.z)); // 6 vertices.Add(new Point3d(p0.x, p1.y, p1.z)); // 7 faces.Add(new Face(start + 0, start + 1, start + 5, start + 4)); // -Y face faces.Add(new Face(start + 1, start + 2, start + 6, start + 5)); // +X face faces.Add(new Face(start + 2, start + 3, start + 7, start + 6)); // +Y face faces.Add(new Face(start + 3, start + 0, start + 4, start + 7)); // -X face faces.Add(new Face(start + 4, start + 5, start + 6, start + 7)); // +Z face faces.Add(new Face(start + 0, start + 3, start + 2, start + 1)); // -Z face }
private void DumpLayoutGeometry( string dumpGeometryPath, DungeonLayout layout) { GeometryFileWriter fileWriter = new GeometryFileWriter(); string filename = string.Format("DungeonLayout_Game{0}_Size{1}", layout.GameID, layout.LayoutWorldTemplate.dungeon_size); string header = string.Format("DungeonLayout for GameID:{0} DungeonSize: {1}", layout.GameID, layout.LayoutWorldTemplate.dungeon_size); string result = SuccessMessages.GENERAL_SUCCESS; Vector3d roomSize = new Vector3d(WorldConstants.ROOM_X_SIZE, WorldConstants.ROOM_Y_SIZE, WorldConstants.ROOM_Z_SIZE); for (DungeonLayout.RoomIndexIterator iterator = new DungeonLayout.RoomIndexIterator(layout.RoomGrid); iterator.Valid; iterator.Next()) { DungeonLayout.RoomIndex roomIndex = iterator.Current; Room room = layout.GetRoomByIndex(roomIndex); AABB3d roomAABB = new AABB3d(room.world_position, room.world_position + roomSize); AABB3d shrunkRoomAABB = roomAABB.ScaleAboutCenter(0.5f); AABB3d centerAABB = roomAABB.ScaleAboutCenter(0.05f); // Add the AABB for this room fileWriter.AppendAABB(shrunkRoomAABB); // Create portal AABBs to all adjacent rooms for (MathConstants.eSignedDirection roomSide = MathConstants.eSignedDirection.first; roomSide < MathConstants.eSignedDirection.count; ++roomSide) { if (room.RoomHasPortalOnSide(roomSide)) { DungeonLayout.RoomIndex neighborRoomIndex = null; switch (roomSide) { case MathConstants.eSignedDirection.positive_x: neighborRoomIndex = roomIndex.Offset(1, 0, 0); break; case MathConstants.eSignedDirection.negative_x: neighborRoomIndex = roomIndex.Offset(-1, 0, 0); break; case MathConstants.eSignedDirection.positive_y: neighborRoomIndex = roomIndex.Offset(0, 1, 0); break; case MathConstants.eSignedDirection.negative_y: neighborRoomIndex = roomIndex.Offset(0, -1, 0); break; case MathConstants.eSignedDirection.positive_z: neighborRoomIndex = roomIndex.Offset(0, 0, 1); break; case MathConstants.eSignedDirection.negative_z: neighborRoomIndex = roomIndex.Offset(0, 0, -1); break; } Room neighborRoom = layout.GetRoomByIndex(neighborRoomIndex); AABB3d neighborRoomAABB = new AABB3d(neighborRoom.world_position, neighborRoom.world_position + roomSize); AABB3d neighborCenterAABB = neighborRoomAABB.ScaleAboutCenter(0.05f); AABB3d portalAABB = centerAABB.EncloseAABB(neighborCenterAABB); fileWriter.AppendAABB(portalAABB); } } // TODO: DumpLayoutGeometry: Color the rooms by teleporter pair } if (!fileWriter.SaveFile(dumpGeometryPath, filename, header, out result)) { _logger.WriteLine("DungeonValidator: WARNING: Failed to save layout geometry file"); _logger.WriteLine(result); } }
public RoomPortal() { portal_id = -1; target_portal_id = -1; boundingBox = new AABB3d(); }
public List <Model3d> CullByFrustum(Frustum3d frustum) { List <Model3d> result = new List <Model3d>(); foreach (var iter in m_modleList) { iter.m_cullFlag = false; } if (m_octree == null) { foreach (var iter in m_modleList) { OBB3d bounds = iter.GetOBB(); if (IntersectionTest3D.Frustum3dWithOBB3d(frustum, bounds)) { result.Add(iter); } } } else { List <OctreeNode> nodes = new List <OctreeNode>(); nodes.Add(m_octree); while (nodes.Count > 0) { OctreeNode active = nodes[0]; nodes.RemoveAt(0); if (active.m_children != null) { // Has child nodes for (int i = 0; i < 8; ++i) { AABB3d bounds = active.m_children[i].m_bounds; if (IntersectionTest3D.Frustum3dWithAABB3d(frustum, bounds)) { nodes.Add(active.m_children[i]); } } } else { // Is leaf node for (int i = 0; i < active.m_models.Count; ++i) { if (!active.m_models[i].m_cullFlag) { OBB3d bounds = active.m_models[i].GetOBB(); if (IntersectionTest3D.Frustum3dWithOBB3d(frustum, bounds)) { active.m_models[i].m_cullFlag = true; result.Add(active.m_models[i]); } } } } } } return(result); }
void InsertLeaf(int leafNodeIndex) { // make sure we're inserting a new leaf DebugHelper.Assert(m_nodes[leafNodeIndex].m_parentNodeIndex == NullIndex); DebugHelper.Assert(m_nodes[leafNodeIndex].m_leftNodeIndex == NullIndex); DebugHelper.Assert(m_nodes[leafNodeIndex].m_rightNodeIndex == NullIndex); // if the tree is empty then we make the root the leaf if (m_rootNodeIndex == NullIndex) { m_rootNodeIndex = leafNodeIndex; return; } // search for the best place to put the new leaf in the tree // we use surface area and depth as search heuristics int treeNodeIndex = m_rootNodeIndex; AABBTreeNode leafNode = m_nodes[leafNodeIndex]; while (!m_nodes[treeNodeIndex].IsLeaf()) { // because of the test in the while loop above we know we are never a leaf inside it AABBTreeNode treeNode = m_nodes[treeNodeIndex]; int leftNodeIndex = treeNode.m_leftNodeIndex; int rightNodeIndex = treeNode.m_rightNodeIndex; AABBTreeNode leftNode = m_nodes[leftNodeIndex]; AABBTreeNode rightNode = m_nodes[rightNodeIndex]; AABB3d combinedAabb = treeNode.m_bounds.Merge(leafNode.m_bounds); FloatL newParentNodeCost = 2.0f * combinedAabb.CalculateSurfaceArea(); FloatL minimumPushDownCost = 2.0f * (combinedAabb.CalculateSurfaceArea() - treeNode.m_bounds.CalculateSurfaceArea()); // use the costs to figure out whether to create a new parent here or descend FloatL costLeft; FloatL costRight; if (leftNode.IsLeaf()) { costLeft = leafNode.m_bounds.Merge(leftNode.m_bounds).CalculateSurfaceArea() + minimumPushDownCost; } else { AABB3d newLeftAabb = leafNode.m_bounds.Merge(leftNode.m_bounds); costLeft = (newLeftAabb.CalculateSurfaceArea() - leftNode.m_bounds.CalculateSurfaceArea()) + minimumPushDownCost; } if (rightNode.IsLeaf()) { costRight = leafNode.m_bounds.Merge(rightNode.m_bounds).CalculateSurfaceArea() + minimumPushDownCost; } else { AABB3d newRightAabb = leafNode.m_bounds.Merge(rightNode.m_bounds); costRight = (newRightAabb.CalculateSurfaceArea() - rightNode.m_bounds.CalculateSurfaceArea()) + minimumPushDownCost; } // if the cost of creating a new parent node here is less than descending in either direction then // we know we need to create a new parent node, errrr, here and attach the leaf to that if (newParentNodeCost < costLeft && newParentNodeCost < costRight) { break; } // otherwise descend in the cheapest direction if (costLeft < costRight) { treeNodeIndex = leftNodeIndex; } else { treeNodeIndex = rightNodeIndex; } } // the leafs sibling is going to be the node we found above and we are going to create a new // parent node and attach the leaf and this item int leafSiblingIndex = treeNodeIndex; AABBTreeNode leafSibling = m_nodes[leafSiblingIndex]; int oldParentIndex = leafSibling.m_parentNodeIndex; int newParentIndex = AllocateNode(); AABBTreeNode newParent = m_nodes[newParentIndex]; newParent.m_parentNodeIndex = oldParentIndex; newParent.m_bounds = leafNode.m_bounds.Merge(leafSibling.m_bounds); // the new parents aabb is the leaf aabb combined with it's siblings aabb newParent.m_leftNodeIndex = leafSiblingIndex; newParent.m_rightNodeIndex = leafNodeIndex; leafNode.m_parentNodeIndex = newParentIndex; leafSibling.m_parentNodeIndex = newParentIndex; if (oldParentIndex == NullIndex) { // the old parent was the root and so this is now the root m_rootNodeIndex = newParentIndex; } else { // the old parent was not the root and so we need to patch the left or right index to // point to the new node AABBTreeNode oldParent = m_nodes[oldParentIndex]; if (oldParent.m_leftNodeIndex == leafSiblingIndex) { oldParent.m_leftNodeIndex = newParentIndex; } else { oldParent.m_rightNodeIndex = newParentIndex; } } // finally we need to walk back up the tree fixing heights and areas treeNodeIndex = leafNode.m_parentNodeIndex; FixUpwardsTree(treeNodeIndex); }