From 16982d721960ef3a087a8a45ad019db0786e3a1b Mon Sep 17 00:00:00 2001 From: dexy Date: Sat, 11 Jan 2020 19:20:14 +1100 Subject: [PATCH] Collisions editing progress --- .../GameFiles/FileTypes/YbnFile.cs | 13 +- CodeWalker.Core/GameFiles/GameFileCache.cs | 4 + CodeWalker.Core/GameFiles/Resources/Bounds.cs | 364 +++++++++++++++++- CodeWalker.Core/World/Space.cs | 6 + Project/ProjectForm.cs | 53 ++- Rendering/Renderer.cs | 2 +- World/WorldInfoForm.cs | 5 + WorldForm.cs | 109 ++++++ 8 files changed, 538 insertions(+), 18 deletions(-) diff --git a/CodeWalker.Core/GameFiles/FileTypes/YbnFile.cs b/CodeWalker.Core/GameFiles/FileTypes/YbnFile.cs index 5918832..ccf40a6 100644 --- a/CodeWalker.Core/GameFiles/FileTypes/YbnFile.cs +++ b/CodeWalker.Core/GameFiles/FileTypes/YbnFile.cs @@ -69,14 +69,11 @@ namespace CodeWalker.GameFiles public bool RemoveBounds(Bounds b) { - return false; - } - public bool RemovePoly(BoundPolygon p) - { - return false; - } - public bool RemoveVertex(BoundVertex v) - { + if (Bounds == b) + { + Bounds = null; + return true; + } return false; } diff --git a/CodeWalker.Core/GameFiles/GameFileCache.cs b/CodeWalker.Core/GameFiles/GameFileCache.cs index 91c13ec..9de4787 100644 --- a/CodeWalker.Core/GameFiles/GameFileCache.cs +++ b/CodeWalker.Core/GameFiles/GameFileCache.cs @@ -3517,6 +3517,7 @@ namespace CodeWalker.GameFiles public void TestYbns() { bool savetest = true; + bool reloadtest = false; var errorfiles = new List(); foreach (RpfFile file in AllRpfs) { @@ -3545,6 +3546,9 @@ namespace CodeWalker.GameFiles var bytes = ybn.Save(); + if (!reloadtest) + { continue; } + string origlen = TextUtil.GetBytesReadable(fentry.FileSize); string bytelen = TextUtil.GetBytesReadable(bytes.Length); diff --git a/CodeWalker.Core/GameFiles/Resources/Bounds.cs b/CodeWalker.Core/GameFiles/Resources/Bounds.cs index 2b9f594..c0206ea 100644 --- a/CodeWalker.Core/GameFiles/Resources/Bounds.cs +++ b/CodeWalker.Core/GameFiles/Resources/Bounds.cs @@ -1133,6 +1133,7 @@ namespace CodeWalker.GameFiles { BuildMaterials(); CalculateQuantum(); + //UpdateEdgeIndices(); //TODO: reinstate this? var list = new List(base.GetReferences()); if (Vertices2 != null) @@ -1553,6 +1554,201 @@ namespace CodeWalker.GameFiles PolygonMaterialIndices = polymats.ToArray(); } + public void UpdateEdgeIndices() + { + //update all triangle edge indices, based on shared vertex indices + + var edgedict = new Dictionary(); + if (Polygons != null) + { + foreach (var poly in Polygons) + { + if (poly is BoundPolygonTriangle btri) + { + var e1 = new BoundEdgeRef(btri.vertIndex1, btri.vertIndex2); + var e2 = new BoundEdgeRef(btri.vertIndex2, btri.vertIndex3); + var e3 = new BoundEdgeRef(btri.vertIndex3, btri.vertIndex1); + + if (edgedict.TryGetValue(e1, out BoundEdge edge1)) + { + if (edge1.Triangle2 != null) + { } + edge1.Triangle2 = btri; + edge1.EdgeID2 = 1; + } + else + { + edgedict[e1] = new BoundEdge(btri, 1); + } + if (edgedict.TryGetValue(e2, out BoundEdge edge2)) + { + if (edge2.Triangle2 != null) + { } + edge2.Triangle2 = btri; + edge2.EdgeID2 = 2; + } + else + { + edgedict[e2] = new BoundEdge(btri, 2); + } + if (edgedict.TryGetValue(e3, out BoundEdge edge3)) + { + if (edge3.Triangle2 != null) + { } + edge3.Triangle2 = btri; + edge3.EdgeID2 = 3; + } + else + { + edgedict[e3] = new BoundEdge(btri, 3); + } + + } + } + + foreach (var kvp in edgedict) + { + var eref = kvp.Key; + var edge = kvp.Value; + + if (edge.Triangle1 == null) + { continue; } + + + if (edge.Triangle2 == null) + { + edge.Triangle1.SetEdgeIndex(edge.EdgeID1, -1); + } + else + { + edge.Triangle1.SetEdgeIndex(edge.EdgeID1, (short)edge.Triangle2.Index); + edge.Triangle2.SetEdgeIndex(edge.EdgeID2, (short)edge.Triangle1.Index); + } + } + + } + + } + + + public bool DeletePolygon(BoundPolygon p) + { + if (Polygons != null) + { + var polys = Polygons.ToList(); + var polymats = PolygonMaterialIndices.ToList(); + var idx = polys.IndexOf(p); + if (idx >= 0) + { + polys.RemoveAt(idx); + polymats.RemoveAt(idx); + Polygons = polys.ToArray(); + PolygonMaterialIndices = polymats.ToArray(); + PolygonsCount = (uint)polys.Count; + + for (int i = 0; i < Polygons.Length; i++) + { + var poly = Polygons[i]; + if (poly is BoundPolygonTriangle btri) + { + if (btri.edgeIndex1 == idx) btri.edgeIndex1 = -1; + if (btri.edgeIndex1 > idx) btri.edgeIndex1--; + if (btri.edgeIndex2 == idx) btri.edgeIndex2 = -1; + if (btri.edgeIndex2 > idx) btri.edgeIndex2--; + if (btri.edgeIndex3 == idx) btri.edgeIndex3 = -1; + if (btri.edgeIndex3 > idx) btri.edgeIndex3--; + } + poly.Index = i; + } + + var verts = p.VertexIndices; + for (int i = 0; i < verts.Length; i++) + { + if (DeleteVertex(verts[i], false)) //delete any orphaned vertices + { + verts = p.VertexIndices;//vertex indices will have changed, need to continue with the new ones! + } + } + + return true; + } + + } + return false; + } + + public bool DeleteVertex(int index, bool deletePolys = true) + { + if (Vertices != null) + { + if (!deletePolys) + { + //if not deleting polys, make sure this vertex isn't used by any + foreach (var poly in Polygons) + { + var pverts = poly.VertexIndices; + for (int i = 0; i < pverts.Length; i++) + { + if (pverts[i] == index) + { + return false; + } + } + } + } + + var verts = Vertices.ToList(); + var verts2 = Vertices2?.ToList(); + var vertcols = VertexColours?.ToList(); + verts.RemoveAt(index); + verts2?.RemoveAt(index); + vertcols?.RemoveAt(index); + Vertices = verts.ToArray(); + Vertices2 = verts2?.ToArray(); + VertexColours = vertcols?.ToArray(); + VerticesCount = (uint)verts.Count; + Vertices2Count = VerticesCount; + + if (Polygons != null) + { + var delpolys = new List(); + + foreach (var poly in Polygons) + { + var pverts = poly.VertexIndices; + for (int i = 0; i < pverts.Length; i++) + { + if (pverts[i] == index) + { + delpolys.Add(poly); + } + if (pverts[i] > index) + { + pverts[i]--; + } + } + poly.VertexIndices = pverts; + } + + if (deletePolys) + { + foreach (var delpoly in delpolys) + { + DeletePolygon(delpoly); + } + } + else + { + if (delpolys.Count > 0) + { } //this shouldn't happen! shouldn't have deleted the vertex if it is used by polys + } + } + + return true; + } + return false; + } + } [TC(typeof(EXP))] public class BoundBVH : BoundGeometry { @@ -2230,6 +2426,41 @@ namespace CodeWalker.GameFiles return res; } + + + + public bool DeleteChild(Bounds child) + { + if (Children?.data_items != null) + { + var children = Children.data_items.ToList(); + var transforms1 = ChildrenTransformation1?.ToList(); + var transforms2 = ChildrenTransformation2?.ToList(); + var bboxes = ChildrenBoundingBoxes?.ToList(); + var flags1 = ChildrenFlags1?.ToList(); + var flags2 = ChildrenFlags2?.ToList(); + var idx = children.IndexOf(child); + if (idx >= 0) + { + children.RemoveAt(idx); + transforms1?.RemoveAt(idx); + transforms2?.RemoveAt(idx); + bboxes?.RemoveAt(idx); + flags1?.RemoveAt(idx); + flags2?.RemoveAt(idx); + Children.data_items = children.ToArray(); + ChildrenTransformation1 = transforms1?.ToArray(); + ChildrenTransformation2 = transforms2?.ToArray(); + ChildrenBoundingBoxes = bboxes?.ToArray(); + ChildrenFlags1 = flags1?.ToArray(); + ChildrenFlags2 = flags2?.ToArray(); + BuildBVH(); + return true; + } + } + return false; + } + } @@ -2266,6 +2497,7 @@ namespace CodeWalker.GameFiles public abstract Vector3 Scale { get; set; } public abstract Vector3 Position { get; set; } public abstract Quaternion Orientation { get; set; } + public abstract int[] VertexIndices { get; set; } public abstract BoundVertexRef NearestVertex(Vector3 p); public abstract void GatherVertices(Dictionary verts); public abstract void Read(byte[] bytes, int offset); @@ -2292,9 +2524,9 @@ namespace CodeWalker.GameFiles public short edgeIndex2 { get; set; } public short edgeIndex3 { get; set; } - public int vertIndex1 { get { return (triIndex1 & 0x7FFF); } } - public int vertIndex2 { get { return (triIndex2 & 0x7FFF); } } - public int vertIndex3 { get { return (triIndex3 & 0x7FFF); } } + public int vertIndex1 { get { return (triIndex1 & 0x7FFF); } set { triIndex1 = (ushort)((value & 0x7FFF) + (vertFlag1 ? 0x8000 : 0)); } } + public int vertIndex2 { get { return (triIndex2 & 0x7FFF); } set { triIndex2 = (ushort)((value & 0x7FFF) + (vertFlag2 ? 0x8000 : 0)); } } + public int vertIndex3 { get { return (triIndex3 & 0x7FFF); } set { triIndex3 = (ushort)((value & 0x7FFF) + (vertFlag3 ? 0x8000 : 0)); } } public bool vertFlag1 { get { return (triIndex1 & 0x8000) > 0; } set { triIndex1 = (ushort)(vertIndex1 + (value ? 0x8000 : 0)); } } public bool vertFlag2 { get { return (triIndex2 & 0x8000) > 0; } set { triIndex2 = (ushort)(vertIndex2 + (value ? 0x8000 : 0)); } } public bool vertFlag3 { get { return (triIndex3 & 0x8000) > 0; } set { triIndex3 = (ushort)(vertIndex3 + (value ? 0x8000 : 0)); } } @@ -2397,6 +2629,22 @@ namespace CodeWalker.GameFiles private Quaternion? OrientationCached; private Vector3? ScaleCached; + public override int[] VertexIndices + { + get + { + return new[] { vertIndex1, vertIndex2, vertIndex3 }; + } + set + { + if (value?.Length >= 3) + { + vertIndex1 = value[0]; + vertIndex2 = value[1]; + vertIndex3 = value[2]; + } + } + } public override BoundVertexRef NearestVertex(Vector3 p) { var d1 = (p - Vertex1).Length(); @@ -2416,6 +2664,30 @@ namespace CodeWalker.GameFiles } } + public void SetEdgeIndex(int edgeid, short polyindex) + { + switch (edgeid) + { + case 1: + if (edgeIndex1 != polyindex) + { } + edgeIndex1 = polyindex; + break; + case 2: + if (edgeIndex2 != polyindex) + { } + edgeIndex2 = polyindex; + break; + case 3: + if (edgeIndex3 != polyindex) + { } + edgeIndex3 = polyindex; + break; + default: + break; + } + } + public BoundPolygonTriangle() { Type = BoundPolygonType.Triangle; @@ -2494,6 +2766,20 @@ namespace CodeWalker.GameFiles } } + public override int[] VertexIndices + { + get + { + return new[] { (int)sphereIndex }; + } + set + { + if (value?.Length >= 1) + { + sphereIndex = (ushort)value[0]; + } + } + } public override BoundVertexRef NearestVertex(Vector3 p) { return new BoundVertexRef(sphereIndex, sphereRadius); @@ -2627,6 +2913,21 @@ namespace CodeWalker.GameFiles private Quaternion? OrientationCached; private Vector3? ScaleCached; + public override int[] VertexIndices + { + get + { + return new[] { (int)capsuleIndex1, (int)capsuleIndex2 }; + } + set + { + if (value?.Length >= 2) + { + capsuleIndex1 = (ushort)value[0]; + capsuleIndex2 = (ushort)value[1]; + } + } + } public override BoundVertexRef NearestVertex(Vector3 p) { var d1 = (p - Vertex1).Length(); @@ -2787,6 +3088,23 @@ namespace CodeWalker.GameFiles private Quaternion? OrientationCached; private Vector3? ScaleCached; + public override int[] VertexIndices + { + get + { + return new[] { (int)boxIndex1, (int)boxIndex2, (int)boxIndex3, (int)boxIndex4 }; + } + set + { + if (value?.Length >= 2) + { + boxIndex1 = (short)value[0]; + boxIndex2 = (short)value[1]; + boxIndex3 = (short)value[2]; + boxIndex4 = (short)value[3]; + } + } + } public override BoundVertexRef NearestVertex(Vector3 p) { var d1 = (p - Vertex1).Length(); @@ -2932,6 +3250,21 @@ namespace CodeWalker.GameFiles private Quaternion? OrientationCached; private Vector3? ScaleCached; + public override int[] VertexIndices + { + get + { + return new[] { (int)cylinderIndex1, (int)cylinderIndex2 }; + } + set + { + if (value?.Length >= 2) + { + cylinderIndex1 = (ushort)value[0]; + cylinderIndex2 = (ushort)value[1]; + } + } + } public override BoundVertexRef NearestVertex(Vector3 p) { var d1 = (p - Vertex1).Length(); @@ -2977,6 +3310,31 @@ namespace CodeWalker.GameFiles } + [TC(typeof(EXP))] public struct BoundEdgeRef //convenience struct for updating edge indices + { + public int Vertex1 { get; set; } + public int Vertex2 { get; set; } + + public BoundEdgeRef(int i1, int i2) + { + Vertex1 = Math.Min(i1, i2); + Vertex2 = Math.Max(i1, i2); + } + } + [TC(typeof(EXP))] public class BoundEdge //convenience class for updating edge indices + { + public BoundPolygonTriangle Triangle1 { get; set; } + public BoundPolygonTriangle Triangle2 { get; set; } + public int EdgeID1 { get; set; } + public int EdgeID2 { get; set; } + + public BoundEdge(BoundPolygonTriangle t1, int e1) + { + Triangle1 = t1; + EdgeID1 = e1; + } + } + [TC(typeof(EXP))] public struct BoundVertexRef //convenience struct for BoundPolygon.NearestVertex and SpaceRayIntersectResult { public int Index { get; set; } diff --git a/CodeWalker.Core/World/Space.cs b/CodeWalker.Core/World/Space.cs index 1089e34..3de5658 100644 --- a/CodeWalker.Core/World/Space.cs +++ b/CodeWalker.Core/World/Space.cs @@ -1105,6 +1105,9 @@ namespace CodeWalker.World { testcomplete = false; continue; } //ybn not loaded yet... var b = ybn.Bounds; + if (b == null) + { continue; } + var bhit = b.RayIntersect(ref ray, res.HitDist); if (bhit.Hit) { @@ -1355,6 +1358,9 @@ namespace CodeWalker.World { testcomplete = false; continue; } //ybn not loaded yet... var b = ybn.Bounds; + if (b == null) + { continue; } + var bhit = b.SphereIntersect(ref sph); res.TryUpdate(ref bhit); } diff --git a/Project/ProjectForm.cs b/Project/ProjectForm.cs index 0a0471a..c2a6ec4 100644 --- a/Project/ProjectForm.cs +++ b/Project/ProjectForm.cs @@ -3136,18 +3136,34 @@ namespace CodeWalker.Project return true; } + var parent = CurrentCollisionBounds.Parent; + bool res = false; if (WorldForm != null) { lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... { - res = CurrentYbnFile.RemoveBounds(CurrentCollisionBounds); + if (parent != null) + { + res = parent.DeleteChild(CurrentCollisionBounds); + } + else + { + res = CurrentYbnFile.RemoveBounds(CurrentCollisionBounds); + } //WorldForm.SelectItem(null, null, null); } } else { - res = CurrentYbnFile.RemoveBounds(CurrentCollisionBounds); + if (parent != null) + { + res = parent.DeleteChild(CurrentCollisionBounds); + } + else + { + res = CurrentYbnFile.RemoveBounds(CurrentCollisionBounds); + } } if (!res) { @@ -3163,8 +3179,20 @@ namespace CodeWalker.Project CurrentCollisionBounds = null; + if (parent != null) + { + if (WorldForm != null) + { + WorldForm.UpdateCollisionBoundsGraphics(parent); + } + } + return true; } + public bool IsCurrentCollisionBounds(Bounds bounds) + { + return bounds == CurrentCollisionBounds; + } public void NewCollisionPoly(BoundPolygonType type, BoundPolygon copy = null) { @@ -3218,13 +3246,13 @@ namespace CodeWalker.Project { lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... { - res = CurrentYbnFile.RemovePoly(CurrentCollisionPoly); + res = CurrentCollisionPoly.Owner.DeletePolygon(CurrentCollisionPoly); //WorldForm.SelectItem(null, null, null); } } else { - res = CurrentYbnFile.RemovePoly(CurrentCollisionPoly); + res = CurrentCollisionPoly.Owner.DeletePolygon(CurrentCollisionPoly); } if (!res) { @@ -3240,8 +3268,17 @@ namespace CodeWalker.Project CurrentCollisionPoly = null; + if (WorldForm != null) + { + WorldForm.UpdateCollisionBoundsGraphics(CurrentCollisionBounds); + } + return true; } + public bool IsCurrentCollisionPoly(BoundPolygon poly) + { + return poly == CurrentCollisionPoly; + } public void AddCollisionVertexToProject() { @@ -3288,13 +3325,13 @@ namespace CodeWalker.Project { lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... { - res = CurrentYbnFile.RemoveVertex(CurrentCollisionVertex); + res = CurrentCollisionVertex.Owner.DeleteVertex(CurrentCollisionVertex.Index); //WorldForm.SelectItem(null, null, null); } } else { - res = CurrentYbnFile.RemoveVertex(CurrentCollisionVertex); + res = CurrentCollisionVertex.Owner.DeleteVertex(CurrentCollisionVertex.Index); } if (!res) { @@ -3312,6 +3349,10 @@ namespace CodeWalker.Project return true; } + public bool IsCurrentCollisionVertex(BoundVertex vertex) + { + return vertex == CurrentCollisionVertex; + } diff --git a/Rendering/Renderer.cs b/Rendering/Renderer.cs index 87bde0c..59adb7b 100644 --- a/Rendering/Renderer.cs +++ b/Rendering/Renderer.cs @@ -3261,7 +3261,7 @@ namespace CodeWalker.Rendering } RenderableBoundComposite rndbc = renderableCache.GetRenderableBoundComp(bounds); - if (rndbc.IsLoaded) + if ((rndbc != null) && rndbc.IsLoaded) { RenderableBoundGeometryInst rbginst = new RenderableBoundGeometryInst(); rbginst.Inst.Renderable = rndbc; diff --git a/World/WorldInfoForm.cs b/World/WorldInfoForm.cs index fc74d4a..9447f3a 100644 --- a/World/WorldInfoForm.cs +++ b/World/WorldInfoForm.cs @@ -179,6 +179,11 @@ namespace CodeWalker SelectionExtensionTabPage.Text = "Archetype Extension"; SelExtensionPropertyGrid.SelectedObject = item.ArchetypeExtension; } + else if (item.CollisionVertex != null) + { + SelectionExtensionTabPage.Text = "Collision Vertex"; + SelExtensionPropertyGrid.SelectedObject = item.CollisionVertex; + } else if (item.CollisionPoly != null) { SelectionExtensionTabPage.Text = "Collision Polygon"; diff --git a/WorldForm.cs b/WorldForm.cs index 7afa796..0959012 100644 --- a/WorldForm.cs +++ b/WorldForm.cs @@ -3841,15 +3841,26 @@ namespace CodeWalker SelExtensionPropertyGrid.SelectedObject = item.ArchetypeExtension; ShowSelectedExtensionTab(true); } + else if (item.CollisionVertex != null) + { + SelExtensionPropertyGrid.SelectedObject = item.CollisionVertex; + ShowSelectedExtensionTab(true, "Coll"); + ToolbarDeleteItemButton.Enabled = true; + ToolbarDeleteItemButton.Text = "Delete collision vertex"; + } else if (item.CollisionPoly != null) { SelExtensionPropertyGrid.SelectedObject = item.CollisionPoly; ShowSelectedExtensionTab(true, "Coll"); + ToolbarDeleteItemButton.Enabled = true; + ToolbarDeleteItemButton.Text = "Delete collision poly"; } else if (item.CollisionBounds != null) { SelExtensionPropertyGrid.SelectedObject = item.CollisionBounds; ShowSelectedExtensionTab(true, "Coll"); + ToolbarDeleteItemButton.Enabled = true; + ToolbarDeleteItemButton.Text = "Delete collision bounds"; } else { @@ -5100,6 +5111,9 @@ namespace CodeWalker else if (SelectedItem.ScenarioNode != null) DeleteScenarioNode(); else if (SelectedItem.Audio?.AudioZone != null) DeleteAudioZone(); else if (SelectedItem.Audio?.AudioEmitter != null) DeleteAudioEmitter(); + else if (SelectedItem.CollisionVertex != null) DeleteCollisionVertex(); + else if (SelectedItem.CollisionPoly != null) DeleteCollisionPoly(); + else if (SelectedItem.CollisionBounds != null) DeleteCollisionBounds(); } private void CopyItem() { @@ -5695,6 +5709,101 @@ namespace CodeWalker ProjectForm.NewAudioEmitter(SelectedItem.Audio, true); } + private void DeleteCollisionVertex() + { + var vertex = SelectedItem.CollisionVertex; + if (vertex == null) return; + + if ((ProjectForm != null) && (ProjectForm.IsCurrentCollisionVertex(vertex))) + { + if (!ProjectForm.DeleteCollisionVertex()) + { + //MessageBox.Show("Unable to delete this collision vertex from the current project. Make sure the ybn file exists in the current project."); + } + else + { + SelectItem(null); + } + } + else + { + //project not open, or vertex not selected there, just remove the vertex from the geometry... + var bgeom = vertex.Owner; + if ((bgeom == null) || (!bgeom.DeleteVertex(vertex.Index))) + { + MessageBox.Show("Unable to remove vertex."); + } + else + { + UpdateCollisionBoundsGraphics(bgeom); + SelectItem(null); + } + } + } + private void DeleteCollisionBounds() + { + var bounds = SelectedItem.CollisionBounds; + if (bounds == null) return; + + if ((ProjectForm != null) && (ProjectForm.IsCurrentCollisionBounds(bounds))) + { + if (!ProjectForm.DeleteCollisionBounds()) + { + //MessageBox.Show("Unable to delete this collision bounds from the current project. Make sure the ybn file exists in the current project."); + } + else + { + SelectItem(null); + } + } + else + { + var parent = bounds.Parent; + if (parent != null) + { + parent.DeleteChild(bounds); + UpdateCollisionBoundsGraphics(parent); + } + else + { + var ybn = bounds.GetRootYbn(); + ybn.RemoveBounds(bounds); + } + + SelectItem(null); + } + } + private void DeleteCollisionPoly() + { + var poly = SelectedItem.CollisionPoly; + if (poly == null) return; + + if ((ProjectForm != null) && (ProjectForm.IsCurrentCollisionPoly(poly))) + { + if (!ProjectForm.DeleteCollisionPoly()) + { + //MessageBox.Show("Unable to delete this collision polygon from the current project. Make sure the ybn file exists in the current project."); + } + else + { + SelectItem(null); + } + } + else + { + //project not open, or polygon not selected there, just remove the vertex from the geometry... + var bgeom = poly.Owner; + if ((bgeom == null) || (!bgeom.DeletePolygon(poly))) + { + MessageBox.Show("Unable to remove polygon."); + } + else + { + UpdateCollisionBoundsGraphics(bgeom); + SelectItem(null); + } + } + } private void SetMouseSelect(bool enable)