public override void Do() { GroupAction actions = new GroupAction("Migrate sounds links"); foreach (LinkTarget oldLinkTarget in _oldShape.LinkTargets) { if ((oldLinkTarget.Name == "Pause") || (oldLinkTarget.Name == "Resume")) { // The _newShape.LinkTargets collection is empty unless the engine instance has been created. // This is the case because the AddShape action has been executed prior to this. foreach (LinkTarget newLinkTarget in _newShape.LinkTargets) { if (newLinkTarget.Name == oldLinkTarget.Name) { foreach (ShapeLink oldShapeLink in oldLinkTarget.Links) { // create links for new shape actions.Add(new LinkAction(newLinkTarget, oldShapeLink)); foreach (ShapeLink ownerShapeLink in oldShapeLink.Links) { if (ownerShapeLink.OwnerShape.GetType().FullName == "SoundEditorPlugin.SoundShape") // old shape class? { if ((ownerShapeLink.Name == "Pause") || (ownerShapeLink.Name == "Resume")) { // delete links for owner of link (e.g. a Triggerbox) to old shape actions.Add(new UnlinkAction(oldShapeLink, ownerShapeLink)); // create links for owner of link (e.g. a Triggerbox) to new shape actions.Add(new LinkAction(oldShapeLink, newLinkTarget)); } } } } } } } } // batch actions and execute in the end so we do not modify collections inside loops actions.Do(); }
/// <summary> /// This function converts all shapes from the old SoundPlugin to the corresponding shapes of the new FmodPlugin /// </summary> void MigrateToFmodShapes() { // If old Sound plugin is not loaded, don't do anything IEditorPluginModule soundPlugin = EditorManager.GetPluginByName("SoundEditorPlugin.EditorPlugin"); if (soundPlugin == null || !soundPlugin.Initialized) return; // collect all sound specific shapes ShapeCollection soundShapes = new ShapeCollection(); foreach (Layer layer in EditorManager.Scene.Layers) if (layer.Modifiable && layer.Loaded) AddSoundShapesRecursive(soundShapes, layer.Root); if (soundShapes.Count == 0) return; // prompt a dialog DialogResult res = EditorManager.ShowMessageBox("Shapes from old Sound Plugin have been found in loaded layers.\n\nShould these be permanently converted to the corresponding shapes of the Fmod Plugin?", "Old Sound Plugin and Fmod Plugin are both loaded", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (res != DialogResult.Yes) return; ShapeCollection newShapes = new ShapeCollection(); int iConvertedCount = 0; if (soundShapes.Count > 0) { GroupAction actions = new GroupAction("Migrate Sound shapes"); foreach (ShapeObject3D oldShape in soundShapes) { ShapeObject3D newShape = null; if (oldShape.GetType().FullName == "SoundEditorPlugin.SoundShape") { newShape = new FmodSoundShape(oldShape.ShapeName); MigrateSoundShapeProperties(oldShape, (FmodSoundShape)newShape); actions.Add(AddShapeAction.CreateAddShapeAction(newShape, oldShape.Parent, oldShape.ParentLayer, false)); actions.Add(new MigrateSoundLinksAction(oldShape, (FmodSoundShape)newShape)); actions.Add(new MigrateChildrenAction(oldShape, newShape)); actions.Add(RemoveShapeAction.CreateRemoveShapeAction(oldShape)); newShapes.Add(newShape); } else if (oldShape.GetType().FullName == "SoundEditorPlugin.SoundCollisionShape") { newShape = new FmodCollisionMeshShape(oldShape.ShapeName); MigrateSoundCollisionShapeProperties(oldShape, (FmodCollisionMeshShape)newShape); actions.Add(AddShapeAction.CreateAddShapeAction(newShape, oldShape.Parent, oldShape.ParentLayer, false)); actions.Add(new MigrateChildrenAction(oldShape, newShape)); actions.Add(RemoveShapeAction.CreateRemoveShapeAction(oldShape)); newShapes.Add(newShape); } if (newShape == null) continue; iConvertedCount++; } // EditorManager.Actions.Add() is not used, in order to prevent a undo of the conversion actions.Do(); } // ensure, that all migrated childs have valid engine instances foreach (ShapeBase shape in newShapes) foreach (ShapeBase child in shape.ChildCollection) child.ReCreateEngineInstance(true); EditorManager.ShowMessageBox(iConvertedCount.ToString() + " Shape(s) have been successfully converted.", "Sound to Fmod shapes conversion", MessageBoxButtons.OK, MessageBoxIcon.Information); }
/// <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> /// This function converts all shapes from the old SoundPlugin to the corresponding shapes of the new FmodPlugin /// </summary> void MigrateToFmodShapes() { // If old Sound plugin is not loaded, don't do anything IEditorPluginModule soundPlugin = EditorManager.GetPluginByName("SoundEditorPlugin.EditorPlugin"); if (soundPlugin == null || !soundPlugin.Initialized) { return; } // collect all sound specific shapes ShapeCollection soundShapes = new ShapeCollection(); foreach (Layer layer in EditorManager.Scene.Layers) { if (layer.Modifiable && layer.Loaded) { AddSoundShapesRecursive(soundShapes, layer.Root); } } if (soundShapes.Count == 0) { return; } // prompt a dialog DialogResult res = EditorManager.ShowMessageBox("Shapes from old Sound Plugin have been found in loaded layers.\n\nShould these be permanently converted to the corresponding shapes of the Fmod Plugin?", "Old Sound Plugin and Fmod Plugin are both loaded", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (res != DialogResult.Yes) { return; } ShapeCollection newShapes = new ShapeCollection(); int iConvertedCount = 0; if (soundShapes.Count > 0) { GroupAction actions = new GroupAction("Migrate Sound shapes"); foreach (ShapeObject3D oldShape in soundShapes) { ShapeObject3D newShape = null; if (oldShape.GetType().FullName == "SoundEditorPlugin.SoundShape") { newShape = new FmodSoundShape(oldShape.ShapeName); MigrateSoundShapeProperties(oldShape, (FmodSoundShape)newShape); actions.Add(AddShapeAction.CreateAddShapeAction(newShape, oldShape.Parent, oldShape.ParentLayer, false)); actions.Add(new MigrateSoundLinksAction(oldShape, (FmodSoundShape)newShape)); actions.Add(new MigrateChildrenAction(oldShape, newShape)); actions.Add(RemoveShapeAction.CreateRemoveShapeAction(oldShape)); newShapes.Add(newShape); } else if (oldShape.GetType().FullName == "SoundEditorPlugin.SoundCollisionShape") { newShape = new FmodCollisionMeshShape(oldShape.ShapeName); MigrateSoundCollisionShapeProperties(oldShape, (FmodCollisionMeshShape)newShape); actions.Add(AddShapeAction.CreateAddShapeAction(newShape, oldShape.Parent, oldShape.ParentLayer, false)); actions.Add(new MigrateChildrenAction(oldShape, newShape)); actions.Add(RemoveShapeAction.CreateRemoveShapeAction(oldShape)); newShapes.Add(newShape); } if (newShape == null) { continue; } iConvertedCount++; } // EditorManager.Actions.Add() is not used, in order to prevent a undo of the conversion actions.Do(); } // ensure, that all migrated childs have valid engine instances foreach (ShapeBase shape in newShapes) { foreach (ShapeBase child in shape.ChildCollection) { child.ReCreateEngineInstance(true); } } EditorManager.ShowMessageBox(iConvertedCount.ToString() + " Shape(s) have been successfully converted.", "Sound to Fmod shapes conversion", MessageBoxButtons.OK, MessageBoxIcon.Information); }
/// <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); }