/// <summary> /// Build nav mesh button /// </summary> private void BuildNavMesh_Click(object sender, EventArgs e) { CSharpFramework.Scene.ZoneCollection zones = EditorManager.Scene.Zones.ShallowClone(); GroupAction groupLoadAction = new GroupAction("Load all zones"); foreach (CSharpFramework.Scene.Zone zone in zones) groupLoadAction.Add(new CSharpFramework.Actions.SetZoneLoadedStatusAction(zone, true)); groupLoadAction.Do(); { // for printing out stats BuildStatisticsRichTextBox.ScrollBars = RichTextBoxScrollBars.ForcedVertical; Font oldFont = BuildStatisticsRichTextBox.SelectionFont; Font newFontPlain = new Font(oldFont, oldFont.Style & ~FontStyle.Bold); Font newFontBold = new Font(oldFont, oldFont.Style | FontStyle.Bold); ShapeCollection navMeshShapes = EditorManager.Scene.AllShapesOfType(typeof(HavokNavMeshShape)); // gather all geometry once (divide by zone later) ShapeCollection staticGeometries = new ShapeCollection(); { int numEntities = 0, numStaticMeshes = 0, numTerrains = 0; int numCarvers = 0, numSeedPoints = 0, numLocalSettings = 0; gatherGeometricShapes(ref staticGeometries, ref numEntities, ref numStaticMeshes, ref numTerrains, ref numCarvers, ref numSeedPoints, ref numLocalSettings); // // print out some debug info // BuildStatisticsRichTextBox.SelectionStart = BuildStatisticsRichTextBox.Text.Length; { String inputGeometryLabel = "Input Geometry"; BuildStatisticsRichTextBox.Text = inputGeometryLabel; } BuildStatisticsRichTextBox.SelectionLength = BuildStatisticsRichTextBox.Text.Length - BuildStatisticsRichTextBox.SelectionStart; BuildStatisticsRichTextBox.SelectionFont = newFontBold; { String inputGlobalGeometryInfo = "\n\nStatic meshes\t: " + numStaticMeshes + "\nTerrains\t\t: " + numTerrains + "\nEntities\t\t: " + numEntities + "\n\nCarvers\t\t: " + numCarvers + "\nSeed points\t: " + numSeedPoints + "\nLocal settings\t: " + numLocalSettings + "\n\n"; BuildStatisticsRichTextBox.Text += inputGlobalGeometryInfo; } BuildStatisticsRichTextBox.SelectionLength = BuildStatisticsRichTextBox.Text.Length - BuildStatisticsRichTextBox.SelectionStart; BuildStatisticsRichTextBox.SelectionFont = newFontPlain; // // debug info end // } // actually build the navmeshes here int numBuiltNavMeshShapes = 0; bool allCompleted = true; foreach (HavokNavMeshShape shape in navMeshShapes) { int numGeometryVertices = 0, numGeometryTriangles = 0; // note that the build function only uses static geometries that lie in the same zone! bool built = shape.Build(staticGeometries, ref numGeometryVertices, ref numGeometryTriangles); if (built) { numBuiltNavMeshShapes++; // // print out some debug info // BuildStatisticsRichTextBox.SelectionStart = BuildStatisticsRichTextBox.Text.Length; { String navMeshLabel = "\n\nNav Mesh #" + numBuiltNavMeshShapes; BuildStatisticsRichTextBox.Text += navMeshLabel; } BuildStatisticsRichTextBox.SelectionLength = BuildStatisticsRichTextBox.Text.Length - BuildStatisticsRichTextBox.SelectionStart; BuildStatisticsRichTextBox.SelectionFont = newFontBold; BuildStatisticsRichTextBox.SelectionStart = BuildStatisticsRichTextBox.Text.Length; { String inputPerNavMeshGeometryInfo = "\nTotal input triangles\t: " + numGeometryTriangles + "\nTotal input vertices\t: " + numGeometryVertices + "\n\n"; int facesSize = shape.GetNavMeshFaceSize() * shape.GetNumNavMeshFaces(); int edgesSize = shape.GetNavMeshEdgeSize() * shape.GetNumNavMeshEdges(); int verticesSize = shape.GetNavMeshVertexSize() * shape.GetNumNavMeshVertices(); int totalSize = shape.GetNavMeshStructSize() + facesSize + edgesSize + verticesSize; String navMeshInfo = "\nTotal size\t\t: " + totalSize + " bytes\nFaces ( " + shape.GetNumNavMeshFaces() + " )\t: " + facesSize + "\nEdges ( " + shape.GetNumNavMeshEdges() + " )\t: " + edgesSize + "\nVertices ( " + shape.GetNumNavMeshVertices() + " )\t: " + verticesSize; BuildStatisticsRichTextBox.Text += navMeshInfo; } BuildStatisticsRichTextBox.SelectionLength = BuildStatisticsRichTextBox.Text.Length - BuildStatisticsRichTextBox.SelectionStart; BuildStatisticsRichTextBox.SelectionFont = newFontPlain; // // debug info end // } else { allCompleted = false; break; } } if (allCompleted) { // stitch the navmeshes together using (HavokAiManaged.EngineInstanceHavokNavMeshLinker linker = new HavokAiManaged.EngineInstanceHavokNavMeshLinker()) { // collect all navmeshes at once foreach (HavokNavMeshShape shape in navMeshShapes) { if (shape.HasEngineInstance()) { linker.AddNavMeshShape(shape._engineInstance.GetNativeObject()); HavokNavMeshGlobalSettings globalSettings = GetGlobalSettings(shape.NavMeshGlobalSettingsKey); if (globalSettings != null) { linker.m_linkEdgeMatchTolerance = globalSettings.LinkEdgeMatchTolerance; linker.m_linkMaxStepHeight = globalSettings.LinkMaxStepHeight; linker.m_linkMaxSeparation = globalSettings.LinkMaxSeparation; linker.m_linkMaxOverhang = globalSettings.LinkMaxOverhang; linker.m_linkCosPlanarAlignmentAngle = (float)Math.Cos(globalSettings.LinkPlanarAlignmentAngle / 180.0f * 3.14159f); linker.m_linkCosVerticalAlignmentAngle = (float)Math.Cos(globalSettings.LinkVerticalAlignmentAngle / 180.0f * 3.14159f); linker.m_linkMinEdgeOverlap = globalSettings.LinkMinEdgeOverlap; } } } // link them together linker.LinkNavMeshes(); } // save it to disk (separate from next loop because we want to guarantee that we don't serialize out some runtime only data) foreach (HavokNavMeshShape shape in navMeshShapes) { shape.SaveNavMeshesToFile(); } // finally load it into the havok ai world foreach (HavokNavMeshShape shape in navMeshShapes) { shape.AddNavMeshToWorld(); } if (EditorManager.InPlayingMode && WantPhysicsConnection()) { HavokAiManaged.ManagedModule.SetConnectToPhysicsWorld(true, false); } } EnableBuildButtonAsterisk(false); //EnableStreamingDependentControls(shape.GetNumNavMeshes()>1); } groupLoadAction.Undo(); EditorManager.ActiveView.UpdateView(true); }
/// <summary> /// Build nav mesh button /// </summary> private void BuildNavMesh_Click(object sender, EventArgs e) { CSharpFramework.Scene.ZoneCollection zones = EditorManager.Scene.Zones.ShallowClone(); GroupAction groupLoadAction = new GroupAction("Load all zones"); foreach (CSharpFramework.Scene.Zone zone in zones) { groupLoadAction.Add(new CSharpFramework.Actions.SetZoneLoadedStatusAction(zone, true)); } groupLoadAction.Do(); { // for printing out stats BuildStatisticsRichTextBox.ScrollBars = RichTextBoxScrollBars.ForcedVertical; Font oldFont = BuildStatisticsRichTextBox.SelectionFont; Font newFontPlain = new Font(oldFont, oldFont.Style & ~FontStyle.Bold); Font newFontBold = new Font(oldFont, oldFont.Style | FontStyle.Bold); ShapeCollection navMeshShapes = EditorManager.Scene.AllShapesOfType(typeof(HavokNavMeshShape)); // gather all geometry once (divide by zone later) ShapeCollection staticGeometries = new ShapeCollection(); { int numEntities = 0, numStaticMeshes = 0, numTerrains = 0; int numCarvers = 0, numSeedPoints = 0, numLocalSettings = 0; gatherGeometricShapes(ref staticGeometries, ref numEntities, ref numStaticMeshes, ref numTerrains, ref numCarvers, ref numSeedPoints, ref numLocalSettings); // // print out some debug info // BuildStatisticsRichTextBox.SelectionStart = BuildStatisticsRichTextBox.Text.Length; { String inputGeometryLabel = "Input Geometry"; BuildStatisticsRichTextBox.Text = inputGeometryLabel; } BuildStatisticsRichTextBox.SelectionLength = BuildStatisticsRichTextBox.Text.Length - BuildStatisticsRichTextBox.SelectionStart; BuildStatisticsRichTextBox.SelectionFont = newFontBold; { String inputGlobalGeometryInfo = "\n\nStatic meshes\t: " + numStaticMeshes + "\nTerrains\t\t: " + numTerrains + "\nEntities\t\t: " + numEntities + "\n\nCarvers\t\t: " + numCarvers + "\nSeed points\t: " + numSeedPoints + "\nLocal settings\t: " + numLocalSettings + "\n\n"; BuildStatisticsRichTextBox.Text += inputGlobalGeometryInfo; } BuildStatisticsRichTextBox.SelectionLength = BuildStatisticsRichTextBox.Text.Length - BuildStatisticsRichTextBox.SelectionStart; BuildStatisticsRichTextBox.SelectionFont = newFontPlain; // // debug info end // } // actually build the navmeshes here int numBuiltNavMeshShapes = 0; bool allCompleted = true; foreach (HavokNavMeshShape shape in navMeshShapes) { int numGeometryVertices = 0, numGeometryTriangles = 0; // note that the build function only uses static geometries that lie in the same zone! bool built = shape.Build(staticGeometries, ref numGeometryVertices, ref numGeometryTriangles); if (built) { numBuiltNavMeshShapes++; // // print out some debug info // BuildStatisticsRichTextBox.SelectionStart = BuildStatisticsRichTextBox.Text.Length; { String navMeshLabel = "\n\nNav Mesh #" + numBuiltNavMeshShapes; BuildStatisticsRichTextBox.Text += navMeshLabel; } BuildStatisticsRichTextBox.SelectionLength = BuildStatisticsRichTextBox.Text.Length - BuildStatisticsRichTextBox.SelectionStart; BuildStatisticsRichTextBox.SelectionFont = newFontBold; BuildStatisticsRichTextBox.SelectionStart = BuildStatisticsRichTextBox.Text.Length; { String inputPerNavMeshGeometryInfo = "\nTotal input triangles\t: " + numGeometryTriangles + "\nTotal input vertices\t: " + numGeometryVertices + "\n\n"; int facesSize = shape.GetNavMeshFaceSize() * shape.GetNumNavMeshFaces(); int edgesSize = shape.GetNavMeshEdgeSize() * shape.GetNumNavMeshEdges(); int verticesSize = shape.GetNavMeshVertexSize() * shape.GetNumNavMeshVertices(); int totalSize = shape.GetNavMeshStructSize() + facesSize + edgesSize + verticesSize; String navMeshInfo = "\nTotal size\t\t: " + totalSize + " bytes\nFaces ( " + shape.GetNumNavMeshFaces() + " )\t: " + facesSize + "\nEdges ( " + shape.GetNumNavMeshEdges() + " )\t: " + edgesSize + "\nVertices ( " + shape.GetNumNavMeshVertices() + " )\t: " + verticesSize; BuildStatisticsRichTextBox.Text += navMeshInfo; } BuildStatisticsRichTextBox.SelectionLength = BuildStatisticsRichTextBox.Text.Length - BuildStatisticsRichTextBox.SelectionStart; BuildStatisticsRichTextBox.SelectionFont = newFontPlain; // // debug info end // } else { allCompleted = false; break; } } if (allCompleted) { // stitch the navmeshes together using (HavokAiManaged.EngineInstanceHavokNavMeshLinker linker = new HavokAiManaged.EngineInstanceHavokNavMeshLinker()) { // collect all navmeshes at once foreach (HavokNavMeshShape shape in navMeshShapes) { if (shape.HasEngineInstance()) { linker.AddNavMeshShape(shape._engineInstance.GetNativeObject()); HavokNavMeshGlobalSettings globalSettings = GetGlobalSettings(shape.NavMeshGlobalSettingsKey); if (globalSettings != null) { linker.m_linkEdgeMatchTolerance = globalSettings.LinkEdgeMatchTolerance; linker.m_linkMaxStepHeight = globalSettings.LinkMaxStepHeight; linker.m_linkMaxSeparation = globalSettings.LinkMaxSeparation; linker.m_linkMaxOverhang = globalSettings.LinkMaxOverhang; linker.m_linkCosPlanarAlignmentAngle = (float)Math.Cos(globalSettings.LinkPlanarAlignmentAngle / 180.0f * 3.14159f); linker.m_linkCosVerticalAlignmentAngle = (float)Math.Cos(globalSettings.LinkVerticalAlignmentAngle / 180.0f * 3.14159f); linker.m_linkMinEdgeOverlap = globalSettings.LinkMinEdgeOverlap; } } } // link them together linker.LinkNavMeshes(); } // save it to disk (separate from next loop because we want to guarantee that we don't serialize out some runtime only data) foreach (HavokNavMeshShape shape in navMeshShapes) { shape.SaveNavMeshesToFile(); } // finally load it into the havok ai world foreach (HavokNavMeshShape shape in navMeshShapes) { shape.AddNavMeshToWorld(); } if (EditorManager.InPlayingMode && WantPhysicsConnection()) { HavokAiManaged.ManagedModule.SetConnectToPhysicsWorld(true); } } EnableBuildButtonAsterisk(false); //EnableStreamingDependentControls(shape.GetNumNavMeshes()>1); } groupLoadAction.Undo(); EditorManager.ActiveView.UpdateView(true); }