// TODO: make selecting variants work when selecting in hierarchy/rect-select too public static void DoSelectionClick(SceneView sceneView, Vector2 mousePosition) { ChiselIntersection intersection; var gameobject = ChiselClickSelectionManager.PickClosestGameObject(mousePosition, out intersection); // If we're a child of an operation that has a "handle as one" flag set, return that instead gameobject = ChiselSceneQuery.FindSelectionBase(gameobject); var selectionType = GetCurrentSelectionType(); var selectedObjectsOnClick = new List <int>(Selection.instanceIDs); switch (selectionType) { case SelectionType.Additive: { if (!gameobject) { break; } ChiselSyncSelection.SelectBrushVariant(intersection.brushIntersection.brush, uniqueSelection: false); var instanceID = gameobject.GetInstanceID(); selectedObjectsOnClick.Add(instanceID); ChiselClickSelectionManager.ignoreSelectionChanged = true; Selection.instanceIDs = selectedObjectsOnClick.ToArray(); break; } case SelectionType.Subtractive: { if (!gameobject) { break; } Undo.RecordObject(ChiselSyncSelection.Instance, "Deselected brush variant"); ChiselSyncSelection.DeselectBrushVariant(intersection.brushIntersection.brush); // Can only deselect brush if all it's synchronized brushes have also been deselected if (!ChiselSyncSelection.IsAnyBrushVariantSelected(intersection.brushIntersection.brush)) { var instanceID = gameobject.GetInstanceID(); selectedObjectsOnClick.Remove(instanceID); } ChiselClickSelectionManager.ignoreSelectionChanged = true; Selection.instanceIDs = selectedObjectsOnClick.ToArray(); return; } default: { Undo.RecordObject(ChiselSyncSelection.Instance, "Selected brush variant"); ChiselSyncSelection.SelectBrushVariant(intersection.brushIntersection.brush, uniqueSelection: true); ChiselClickSelectionManager.ignoreSelectionChanged = true; Selection.activeGameObject = gameobject; break; } } }
// For each brush // 1D: // Find surfaces that intersect with ray // Find edges on that surface, if intersection is close enough to edge, find closest point on edge static void FindSnapPointsAlongRay(GameObject[] selection, Vector3 worldRayStart, Vector3 worldRayDirection, List <SurfaceSnap> allSurfaceSnapEvents, List <EdgeSnap> allEdgeSnapEvents, List <VertexSnap> allVertexSnapEvents) { if (selection == null || selection.Length == 0) { return; } if (allSurfaceSnapEvents == null && allEdgeSnapEvents == null && allVertexSnapEvents == null) { return; } s_FoundIntersections.Clear(); if (ChiselSceneQuery.FindFirstWorldIntersection(s_FoundIntersections, worldRayStart - worldRayDirection, worldRayStart + worldRayDirection, filter: selection)) { if (allSurfaceSnapEvents != null) { for (int i = 0; i < s_FoundIntersections.Count; i++) { var intersection = s_FoundIntersections[i]; allSurfaceSnapEvents.Add(new SurfaceSnap { brush = intersection.brushIntersection.brush, surfaceIndex = intersection.brushIntersection.surfaceIndex, intersection = intersection.worldPlaneIntersection, normal = intersection.worldPlane.normal, }); } } } if (allEdgeSnapEvents == null && allVertexSnapEvents == null) { return; } foreach (var intersection in s_FoundIntersections) { var csgBrush = intersection.brushIntersection.brush; var csgTree = intersection.brushIntersection.tree; var brushMeshBlob = BrushMeshManager.GetBrushMeshBlob(csgBrush.BrushMesh); if (!brushMeshBlob.IsCreated) { continue; } ref var brushMesh = ref brushMeshBlob.Value; ref var polygons = ref brushMesh.polygons;
internal static GameObject PickNodeOrGameObject(Camera camera, Vector2 pickposition, int layers, ref GameObject[] ignore, ref GameObject[] filter, out ChiselModel model, out ChiselNode node, out CSGTreeBrushIntersection intersection) { TryNextSelection: intersection = new CSGTreeBrushIntersection { surfaceID = -1, brushUserID = -1 }; model = null; node = null; Material sharedMaterial; var gameObject = PickModel(camera, pickposition, layers, ref ignore, ref filter, out model, out sharedMaterial); if (object.Equals(gameObject, null)) { return(null); } if (model) { int filterLayerParameter0 = (sharedMaterial) ? sharedMaterial.GetInstanceID() : 0; { var worldRay = camera.ScreenPointToRay(pickposition); var worldRayStart = worldRay.origin; var worldRayVector = (worldRay.direction * (camera.farClipPlane - camera.nearClipPlane)); var worldRayEnd = worldRayStart + worldRayVector; CSGTreeBrushIntersection tempIntersection; if (ChiselSceneQuery.FindFirstWorldIntersection(model, worldRayStart, worldRayEnd, filterLayerParameter0, layers, ignore, filter, out tempIntersection)) { var clickedBrush = tempIntersection.brush; node = CSGNodeHierarchyManager.FindCSGNodeByInstanceID(clickedBrush.UserID); if (node) { if (ignore != null && ignore.Contains(node.gameObject)) { node = null; return(null); } intersection = tempIntersection; return(node.gameObject); } else { node = null; } } } if (ignore == null) { return(null); } ArrayUtility.Add(ref ignore, gameObject); goto TryNextSelection; } if (object.Equals(gameObject, null)) { return(null); } if (ignore != null && ignore.Contains(gameObject)) { return(null); } return(gameObject); }
internal static void Update(SceneView sceneView) { if (!ChiselRectSelection.Valid) { prevStartGUIPoint = new Vector2(float.PositiveInfinity, float.PositiveInfinity); prevMouseGUIPoint = prevStartGUIPoint; prevStartScreenPoint = Vector2.zero; prevMouseScreenPoint = Vector2.zero; rectFoundGameObjects.Clear(); rectFoundTreeNodes.Clear(); return; } ChiselRectSelection.SceneView = sceneView; var rectSelectionID = ChiselRectSelection.RectSelectionID; var hotControl = GUIUtility.hotControl; var areRectSelecting = hotControl == rectSelectionID; var typeForControl = Event.current.GetTypeForControl(rectSelectionID); // check if we're rect-selecting if (areRectSelecting) { if ((typeForControl == EventType.Used || Event.current.commandName == "ModifierKeysChanged") && ChiselRectSelection.RectSelecting) { var selectStartPoint = ChiselRectSelection.SelectStartPoint; var selectMousePoint = ChiselRectSelection.SelectMousePoint; // determine if our frustum changed since the last time bool modified = false; bool needUpdate = false; if (prevStartGUIPoint != selectStartPoint) { prevStartGUIPoint = selectStartPoint; prevStartScreenPoint = Event.current.mousePosition; needUpdate = true; } if (prevMouseGUIPoint != selectMousePoint) { prevMouseGUIPoint = selectMousePoint; prevMouseScreenPoint = Event.current.mousePosition; needUpdate = true; } if (needUpdate) { var rect = ChiselCameraUtility.PointsToRect(prevStartScreenPoint, prevMouseScreenPoint); if (rect.width > 3 && rect.height > 3) { var frustum = ChiselCameraUtility.GetCameraSubFrustum(Camera.current, rect); var selectionType = GetCurrentSelectionType(); if (selectionType == SelectionType.Replace) { rectFoundTreeNodes.Clear(); rectFoundGameObjects.Clear(); } // Find all the brushes (and it's gameObjects) that are inside the frustum if (!ChiselSceneQuery.GetNodesInFrustum(frustum, UnityEditor.Tools.visibleLayers, ref rectFoundTreeNodes)) { if (rectFoundGameObjects != null && rectFoundGameObjects.Count > 0) { rectFoundTreeNodes.Clear(); rectFoundGameObjects.Clear(); modified = true; } } else { modified = true; } foreach (var treeNode in rectFoundTreeNodes) { var brush = (CSGTreeBrush)treeNode; if (brush.Valid) { switch (selectionType) { case SelectionType.Additive: { ChiselSyncSelection.SelectBrushVariant(brush, uniqueSelection: false); break; } case SelectionType.Subtractive: { ChiselSyncSelection.DeselectBrushVariant(brush); break; } default: { ChiselSyncSelection.SelectBrushVariant(brush, uniqueSelection: true); break; } } } var nodeComponent = ChiselNodeHierarchyManager.FindChiselNodeByTreeNode(treeNode); if (!nodeComponent) { continue; } var gameObject = nodeComponent.gameObject; rectFoundGameObjects.Add(gameObject); } } } UnityEngine.Object[] currentSelection = null; var originalLastSelection = ChiselRectSelection.LastSelection; var originalSelectionStart = ChiselRectSelection.SelectionStart; if (modified && rectFoundGameObjects != null && rectFoundGameObjects.Count > 0) { foreach (var obj in rectFoundGameObjects) { // if it hasn't already been added, add the obj if (!originalLastSelection.ContainsKey(obj)) { originalLastSelection.Add(obj, false); } } currentSelection = originalLastSelection.Keys.ToArray(); ChiselRectSelection.CurrentSelection = currentSelection; } else { if (currentSelection == null || modified) { currentSelection = originalLastSelection.Keys.ToArray(); } } if (RemoveGeneratedMeshesFromArray(ref originalSelectionStart)) { modified = true; } if (currentSelection != null && RemoveGeneratedMeshesFromArray(ref currentSelection)) { modified = true; } if ((Event.current.commandName == "ModifierKeysChanged" || modified)) { var foundObjects = currentSelection; RemoveGeneratedMeshesFromArray(ref foundObjects); // calling static method UpdateSelection of RectSelection ChiselRectSelection.UpdateSelection(originalSelectionStart, foundObjects, GetCurrentSelectionType()); } } hotControl = GUIUtility.hotControl; } if (hotControl != rectSelectionID) { prevStartGUIPoint = Vector2.zero; prevMouseGUIPoint = Vector2.zero; rectFoundGameObjects.Clear(); rectFoundTreeNodes.Clear(); } /*else * if (ignoreRect) * { * hotControl = 0; * GUIUtility.hotControl = 0; * } */ bool click = false; var evt = Event.current; switch (typeForControl) { case EventType.MouseDown: { rectClickDown = (Event.current.button == 0 && areRectSelecting); clickMousePosition = Event.current.mousePosition; mouseDragged = false; break; } case EventType.MouseUp: { if (!mouseDragged) { if ((UnityEditor.HandleUtility.nearestControl != 0 || evt.button != 0) && (GUIUtility.keyboardControl != 0 || evt.button != 2)) { break; } click = true; Event.current.Use(); } rectClickDown = false; break; } case EventType.MouseMove: { rectClickDown = false; break; } case EventType.MouseDrag: { mouseDragged = true; break; } case EventType.Used: { if (!mouseDragged) { var delta = Event.current.mousePosition - clickMousePosition; if (Mathf.Abs(delta.x) > 4 || Mathf.Abs(delta.y) > 4) { mouseDragged = true; } } if (mouseDragged || !rectClickDown || Event.current.button != 0 || ChiselRectSelection.RectSelecting) { rectClickDown = false; break; } click = true; Event.current.Use(); break; } case EventType.KeyUp: { if (hotControl == 0 && Event.current.keyCode == UnityEngine.KeyCode.Escape) { if (GUIUtility.hotControl == 0 && // make sure we're not actively doing anything Tools.current != Tool.Custom) { // This deselects everything and disables all tool modes Selection.activeTransform = null; Event.current.Use(); } } break; } case EventType.ValidateCommand: { if (Event.current.commandName != "SelectAll") { break; } Event.current.Use(); break; } case EventType.ExecuteCommand: { if (Event.current.commandName != "SelectAll") { break; } var transforms = new List <UnityEngine.Object>(); for (int sceneIndex = 0; sceneIndex < SceneManager.sceneCount; sceneIndex++) { var scene = SceneManager.GetSceneAt(sceneIndex); foreach (var gameObject in scene.GetRootGameObjects()) { foreach (var transform in gameObject.GetComponentsInChildren <Transform>()) { if ((transform.hideFlags & (HideFlags.NotEditable | HideFlags.HideInHierarchy)) == (HideFlags.NotEditable | HideFlags.HideInHierarchy)) { continue; } transforms.Add(transform.gameObject); } } } var foundObjects = transforms.ToArray(); RemoveGeneratedMeshesFromArray(ref foundObjects); Selection.objects = foundObjects; Event.current.Use(); break; } /* * case EventType.ValidateCommand: * { * if (Event.current.commandName == "SelectAll") * { * Event.current.Use(); * break; * } * if (Keys.HandleSceneValidate(EditModeManager.CurrentTool, true)) * { * Event.current.Use(); * HandleUtility.Repaint(); * } * break; * } * case EventType.ExecuteCommand: * { * if (Event.current.commandName == "SelectAll") * { * var transforms = new List<UnityEngine.Object>(); * for (int sceneIndex = 0; sceneIndex < SceneManager.sceneCount; sceneIndex++) * { * var scene = SceneManager.GetSceneAt(sceneIndex); * foreach (var gameObject in scene.GetRootGameObjects()) * { * foreach (var transform in gameObject.GetComponentsInChildren<Transform>()) * { * if ((transform.hideFlags & (HideFlags.NotEditable | HideFlags.HideInHierarchy)) == (HideFlags.NotEditable | HideFlags.HideInHierarchy)) * continue; * transforms.Add(transform.gameObject); * } * } * } * Selection.objects = transforms.ToArray(); * * Event.current.Use(); * break; * } * break; * } * * case EventType.KeyDown: * { * if (Keys.HandleSceneKeyDown(EditModeManager.CurrentTool, true)) * { * Event.current.Use(); * HandleUtility.Repaint(); * } * break; * } * * case EventType.KeyUp: * { * if (Keys.HandleSceneKeyUp(EditModeManager.CurrentTool, true)) * { * Event.current.Use(); * HandleUtility.Repaint(); * } * break; * } */ } if (click) { // make sure GeneratedMeshes are not part of our selection RemoveGeneratedMeshesFromSelection(); DoSelectionClick(sceneView, Event.current.mousePosition); } }
static GameObject PickNodeOrGameObject(Camera camera, Vector2 pickposition, int layers, ref GameObject[] ignore, ref GameObject[] filter, out ChiselModel model, out ChiselNode node, out ChiselIntersection intersection) { TryNextSelection: intersection = ChiselIntersection.None; node = null; Material sharedMaterial; var gameObject = PickModelOrGameObject(camera, pickposition, layers, ref ignore, ref filter, out model, out sharedMaterial); if (object.Equals(gameObject, null)) { return(null); } if (ChiselGeneratedComponentManager.IsValidModelToBeSelected(model)) { int filterLayerParameter0 = (sharedMaterial) ? sharedMaterial.GetInstanceID() : 0; { var worldRay = camera.ScreenPointToRay(pickposition); var worldRayStart = worldRay.origin; var worldRayVector = (worldRay.direction * (camera.farClipPlane - camera.nearClipPlane)); var worldRayEnd = worldRayStart + worldRayVector; if (ChiselSceneQuery.FindFirstWorldIntersection(model, worldRayStart, worldRayEnd, filterLayerParameter0, layers, ignore, filter, out var tempIntersection)) { node = tempIntersection.node; if (node) { if (ignore != null && ignore.Contains(node.gameObject)) { node = null; return(null); } intersection = tempIntersection; return(node.gameObject); } else { node = null; } } } if (ignore == null) { return(null); } ArrayUtility.Add(ref ignore, gameObject); goto TryNextSelection; } if (object.Equals(gameObject, null)) { return(null); } if (ignore != null && ignore.Contains(gameObject)) { return(null); } return(gameObject); }
// For each brush // 1D: // Find surfaces that intersect with ray // Find edges on that surface, if intersection is close enough to edge, find closest point on edge static void FindSnapPointsAlongRay(GameObject[] selection, Vector3 worldRayStart, Vector3 worldRayDirection, List <SurfaceSnap> allSurfaceSnapEvents, List <EdgeSnap> allEdgeSnapEvents, List <VertexSnap> allVertexSnapEvents) { if (selection == null || selection.Length == 0) { return; } if (allSurfaceSnapEvents == null && allEdgeSnapEvents == null && allVertexSnapEvents == null) { return; } s_FoundIntersections.Clear(); if (ChiselSceneQuery.FindFirstWorldIntersection(s_FoundIntersections, worldRayStart - worldRayDirection, worldRayStart + worldRayDirection, filter: selection)) { if (allSurfaceSnapEvents != null) { for (int i = 0; i < s_FoundIntersections.Count; i++) { var intersection = s_FoundIntersections[i]; allSurfaceSnapEvents.Add(new SurfaceSnap { brush = intersection.brushIntersection.brush, surfaceIndex = intersection.brushIntersection.surfaceIndex, intersection = intersection.worldPlaneIntersection, normal = intersection.worldPlane.normal, }); } } } if (allEdgeSnapEvents == null && allVertexSnapEvents == null) { return; } foreach (var intersection in s_FoundIntersections) { var csgBrush = intersection.brushIntersection.brush; var csgTree = intersection.brushIntersection.tree; var brushMesh = BrushMeshManager.GetBrushMesh(csgBrush.BrushMesh); var polygons = brushMesh.polygons; var halfEdges = brushMesh.halfEdges; var vertices = brushMesh.vertices; var halfEdgePolygonIndices = brushMesh.halfEdgePolygonIndices; var model = ChiselNodeHierarchyManager.FindChiselNodeByInstanceID(csgTree.UserID) as ChiselModel; var worldToNode = csgBrush.TreeToNodeSpaceMatrix * model.hierarchyItem.WorldToLocalMatrix; var nodeToWorld = model.hierarchyItem.LocalToWorldMatrix * csgBrush.NodeToTreeSpaceMatrix; var brushRayStart = worldToNode.MultiplyPoint(worldRayStart); var brushRayDirection = worldToNode.MultiplyVector(worldRayDirection).normalized; var surfaceIndex = intersection.brushIntersection.surfaceIndex; var polygon = polygons[surfaceIndex]; var firstEdge = polygon.firstEdge; var lastEdge = firstEdge + polygon.edgeCount; for (int e0 = lastEdge - 1, e1 = firstEdge; e1 < lastEdge; e0 = e1, e1++) { var i0 = halfEdges[e0].vertexIndex; var i1 = halfEdges[e1].vertexIndex; var v0 = vertices[i0]; var v1 = vertices[i1]; var result = ClosestPointsBetweenTwoLines(brushRayStart, brushRayDirection, v0, v1, out Vector3 A, out Vector3 B); if (result == ClosestLineResult.None) { continue; } if (result == ClosestLineResult.Aligned) { // TODO: draw edge as being intersecting if we're on the edge right now continue; } var dist = (A - B).magnitude; if (dist > kEdgeDistanceEpsilon) { continue; } if (allVertexSnapEvents != null) { var vertDist = ((Vector3)v0 - B).magnitude; if (vertDist < kVertexDistanceEpsilon) { allVertexSnapEvents.Add(new VertexSnap { brush = csgBrush, surfaceIndex = surfaceIndex, vertexIndex = i0, intersection = nodeToWorld.MultiplyPoint(v0) }); } vertDist = ((Vector3)v1 - B).magnitude; if (vertDist < kVertexDistanceEpsilon) { allVertexSnapEvents.Add(new VertexSnap { brush = csgBrush, surfaceIndex = surfaceIndex, vertexIndex = i1, intersection = nodeToWorld.MultiplyPoint(v1) }); } } if (allEdgeSnapEvents != null) { allEdgeSnapEvents.Add(new EdgeSnap { brush = csgBrush, surfaceIndex0 = surfaceIndex, surfaceIndex1 = halfEdgePolygonIndices[halfEdges[e1].twinIndex], vertexIndex0 = i0, vertexIndex1 = i1, intersection = nodeToWorld.MultiplyPoint(B), from = nodeToWorld.MultiplyPoint(v0), to = nodeToWorld.MultiplyPoint(v1) }); } } } }