private static bool StartToolDragging() { jumpedMousePosition += Event.current.delta; Event.current.Use(); if (ToolIsDragging) { UpdateDragVector(); return(false); } // We set ToolIsDragging to true to be able to tell the difference between dragging and clicking ToolIsDragging = true; // Find the intersecting surfaces startSurfaceReference = hoverSurfaceReference; var currentIntersection = hoverIntersection.Value.surfaceIntersection; selectedSurfaceReferences = ChiselSurfaceSelectionManager.Selection.ToArray(); // We need all the brushContainerAssets for all the surfaces we're moving, so that we can record them for an undo selectedBrushContainerAsset = ChiselSurfaceSelectionManager.SelectedBrushMeshes.ToArray(); // We copy all the original surface uvMatrices, so we always apply rotations and transformations relatively to the original // This makes it easier to recover from edge cases and makes it more accurate, floating point wise. selectedUVMatrices = new UVMatrix[selectedSurfaceReferences.Length]; for (int i = 0; i < selectedSurfaceReferences.Length; i++) { if (selectedSurfaceReferences[i].Polygon.surface == null) { selectedUVMatrices[i] = UVMatrix.identity; } else { selectedUVMatrices[i] = selectedSurfaceReferences[i].Polygon.surface.surfaceDescription.UV0; } } // Find the intersection point/plane in model space var nodeTransform = startSurfaceReference.node.hierarchyItem.Transform; var modelTransform = CSGNodeHierarchyManager.FindModelTransformOfTransform(nodeTransform); worldStartPosition = modelTransform.localToWorldMatrix.MultiplyPoint(hoverIntersection.Value.surfaceIntersection.worldIntersection); worldProjectionPlane = modelTransform.localToWorldMatrix.TransformPlane(hoverIntersection.Value.surfaceIntersection.worldPlane); worldIntersection = worldStartPosition; // TODO: we want to be able to determine delta movement over a plane. Ideally it would match the position of the cursor perfectly. // unfortunately when moving the cursor towards the horizon of the plane, relative to the camera, the delta movement // becomes too large or even infinity. Ideally we'd switch to a camera facing plane for these cases and determine movement in // a less perfect way that would still allow the user to move or rotate things in a reasonable way. // more accurate for small movements worldDragPlane = worldProjectionPlane; // TODO: (unfinished) prevents drag-plane from intersecting near plane (makes movement slow down to a singularity when further away from click position) //worldDragPlane = new Plane(Camera.current.transform.forward, worldStartPosition); // TODO: ideally we'd interpolate the behavior of the worldPlane between near and far behavior UpdateDragVector(); return(true); }
internal override void UpdateTransformation() { // TODO: recalculate transformation based on hierarchy up to (but not including) model var transform = hierarchyItem.Transform; if (!transform) { return; } var localToWorldMatrix = transform.localToWorldMatrix; var modelTransform = CSGNodeHierarchyManager.FindModelTransformOfTransform(transform); if (modelTransform) { localTransformation = modelTransform.worldToLocalMatrix * localToWorldMatrix; } else { localTransformation = localToWorldMatrix; } if (ValidNodes) { UpdateInternalTransformation(); } }
void UpdateSurfaceSelection() { surfaceOutlines.Clear(); var selection = ChiselSurfaceSelectionManager.Selection; var hovered = ChiselSurfaceSelectionManager.Hovered; if (selection.Count == 0 && hovered.Count == 0) { surfaceOutlines.Clear(); surfaceOutlineRenderer.Clear(); } else { var allSurfaces = new HashSet <SurfaceReference>(selection); allSurfaces.AddRange(hovered); foreach (var outline in surfaceOutlines.Keys) { var surface = outline.surface; if (!allSurfaces.Contains(surface) || !surface.TreeBrush.Valid || surface.TreeBrush.BrushMesh == BrushMeshInstance.InvalidInstance) { removedSurfaces.Add(outline); } else { allSurfaces.Remove(surface); } } if (removedSurfaces.Count > 0) { foreach (var outline in removedSurfaces) { surfaceOutlines.Remove(outline); } } removedSurfaces.Clear(); foreach (var surface in allSurfaces) { var transform = CSGNodeHierarchyManager.FindModelTransformOfTransform(surface.node.hierarchyItem.Transform); var outline = new SurfaceOutline(transform, surface); foundSurfaceOutlines.Add(outline); } foreach (var outline in foundSurfaceOutlines) { if (!outline.surface.TreeBrush.Valid || outline.surface.TreeBrush.BrushMesh == BrushMeshInstance.InvalidInstance) { continue; } var wireframe = CSGWireframe.CreateWireframe(outline.surface.TreeBrush, outline.surface.surfaceID); surfaceOutlines[outline] = wireframe; } } foundSurfaceOutlines.Clear(); updateSurfaceWireframe = true; }
static void OnMoveTool() { var position = Tools.handlePosition; var rotation = Tools.handleRotation; #if SYNC_SUPPORT // TODO: finish and fix this var selectedNodes = Selection.GetFiltered <CSGNode>(SelectionMode.Editable | SelectionMode.TopLevel); if (selectedNodes.Length == 0) { // TODO: probably need to use our own PositionHandle on non CSG objects, to be able to snap to grid return; } var transformation = Matrix4x4.identity; var invTransformation = Matrix4x4.identity; // TODO: figure out how to handle this with selecting multiple variants of the same brush (synchronized brushes) if (selectedNodes.Length == 1) { foundTreeBrushes.Clear(); selectedNodes[0].GetAllTreeBrushes(foundTreeBrushes, ignoreSynchronizedBrushes: true); if (foundTreeBrushes.Count == 1) { var transform = CSGNodeHierarchyManager.FindModelTransformOfTransform(selectedNodes[0].hierarchyItem.Transform); var firstBrush = foundTreeBrushes.First(); var brush = firstBrush; if (!CSGSyncSelection.IsBrushVariantSelected(brush)) { List <CSGTreeBrush> selectedVariants = new List <CSGTreeBrush>(); if (CSGSyncSelection.GetSelectedVariantsOfBrush(brush, selectedVariants)) { brush = selectedVariants[0]; } } if (transform) { transformation = transform.localToWorldMatrix * brush.NodeToTreeSpaceMatrix; } else { transformation = brush.NodeToTreeSpaceMatrix; } rotation = Quaternion.LookRotation(transformation.GetColumn(2), transformation.GetColumn(1)); invTransformation = selectedNodes[0].transform.localToWorldMatrix * transformation.inverse; if (Tools.pivotRotation == PivotRotation.Global) { rotation = Quaternion.identity; } position = transformation.GetColumn(3); } } #endif EditorGUI.BeginChangeCheck(); // TODO: make this work with bounds! var newPosition = UnitySceneExtensions.SceneHandles.PositionHandle(position, rotation); if (EditorGUI.EndChangeCheck()) { var delta = newPosition - position; var transforms = Selection.transforms; if (transforms != null && transforms.Length > 0) { MoveTransformsTo(transforms, delta); } } }
void UpdateBrushSelection() { brushDirectlySelected.Clear(); var objects = Selection.objects; if (objects.Length > 0) { for (int i = 0; i < objects.Length; i++) { var obj = objects[i]; ChiselNode[] nodes = null; var gameObject = obj as GameObject; if (!Equals(null, gameObject)) { nodes = gameObject.GetComponentsInChildren <ChiselNode>(); } else { var behaviour = obj as Behaviour; if (!Equals(null, behaviour)) { nodes = behaviour.GetComponents <ChiselNode>(); } } if (nodes != null && nodes.Length > 0) { for (int n = 0; n < nodes.Length; n++) { var node = nodes[n]; foundTreeBrushes.Clear(); node.GetAllTreeBrushes(foundTreeBrushes, ignoreSynchronizedBrushes: true); if (foundTreeBrushes.Count > 0) { var directSelected = (// if component is directly select (gameObject == null) || // or when the component is part of the selected gameObject (gameObject == node.gameObject)) && // if we find CSGTreeBrushes directly on this node, but this node // can also have child nodes, then we assume the CSGTreeBrushes are generated // and we don't want to show those as directly selected !node.CanHaveChildNodes; var transform = CSGNodeHierarchyManager.FindModelTransformOfTransform(node.hierarchyItem.Transform); foreach (var treeBrush in foundTreeBrushes) { if (directSelected) { brushDirectlySelected.Add(treeBrush); } var outline = new BrushOutline(transform, treeBrush); foundBrushOutlines.Add(outline); } } } } } } if (foundTreeBrushes.Count == 0) { brushOutlines.Clear(); brushOutlineRenderer.Clear(); } else { foreach (var outline in brushOutlines.Keys) { if (!foundBrushOutlines.Contains(outline) || !outline.brush.Valid || outline.brush.BrushMesh == BrushMeshInstance.InvalidInstance) { removedBrushes.Add(outline); } } if (removedBrushes.Count > 0) { foreach (var outline in removedBrushes) { brushOutlines.Remove(outline); } } removedBrushes.Clear(); foreach (var outline in foundBrushOutlines) { if (!outline.brush.Valid || outline.brush.BrushMesh == BrushMeshInstance.InvalidInstance) { continue; } var wireframe = CSGWireframe.CreateWireframe(outline.brush); brushOutlines[outline] = wireframe; } } foundBrushOutlines.Clear(); updateBrushWireframe = true; }