static void DisableTool()
        {
            EditorGUIUtility.SetWantsMouseJumping(0);               // disable allowing the user to move the mouse over the bounds of the screen
            GUIUtility.hotControl = GUIUtility.keyboardControl = 0; // remove the active control so that the user can use another control
            Event.current.Use();                                    // make sure no-one else can use our event


            toolSnapOverrides = (UVSnapSettings) ~0;
            pointHasSnapped   = false;
        }
Example #2
0
        static void SnapSurfaceVertices(UVSnapSettings snapSettings, SurfaceReference surfaceReference, Vector3 intersectionPoint, float preferenceFactor, ref Vector3 snappedPoint, ref float bestDist)
        {
            if (surfaceReference == null)
            {
                return;
            }

            if ((snapSettings & UVSnapSettings.GeometryVertices) == UVSnapSettings.None)
            {
                return;
            }

            var localToWorldSpace = surfaceReference.LocalToWorldSpace;
            var brushMesh         = surfaceReference.BrushMesh;

            if (brushMesh == null)
            {
                return;
            }
            Debug.Assert(surfaceReference.surfaceIndex >= 0 && surfaceReference.surfaceIndex < brushMesh.polygons.Length);

            var polygon   = brushMesh.polygons[surfaceReference.surfaceIndex];
            var edges     = brushMesh.halfEdges;
            var vertices  = brushMesh.vertices;
            var firstEdge = polygon.firstEdge;
            var lastEdge  = firstEdge + polygon.edgeCount;

            var bestDistSqr = float.PositiveInfinity;
            var bestVertex  = snappedPoint;

            for (int e = firstEdge; e < lastEdge; e++)
            {
                var worldSpaceVertex = localToWorldSpace.MultiplyPoint(vertices[edges[e].vertexIndex]);
                var dist_sqr         = (worldSpaceVertex - intersectionPoint).sqrMagnitude;
                if (dist_sqr < bestDistSqr)
                {
                    bestDistSqr = dist_sqr;
                    bestVertex  = worldSpaceVertex;
                }
            }

            if (float.IsInfinity(bestDistSqr))
            {
                return;
            }

            var closestVertexDistance = Mathf.Sqrt(bestDistSqr) * preferenceFactor;

            if (closestVertexDistance < bestDist)
            {
                bestDist     = closestVertexDistance;
                snappedPoint = bestVertex;
            }
        }
        static void EnableTool(int id)
        {
            EditorGUIUtility.SetWantsMouseJumping(1);                // enable allowing the user to move the mouse over the bounds of the screen
            jumpedMousePosition = Event.current.mousePosition;       // remember the current mouse position so we can update it using Event.current.delta,
                                                                     // since mousePosition won't make sense any more when mouse jumping
            GUIUtility.hotControl = GUIUtility.keyboardControl = id; // set our tool as the active control
            Event.current.Use();                                     // make sure no-one else can use our event


            toolSnapOverrides = (UVSnapSettings) ~0;
            pointHasSnapped   = false;
        }
        static void SnapSurfaceEdges(UVSnapSettings snapSettings, SurfaceReference surfaceReference, Vector3 intersectionPoint, float preferenceFactor, ref Vector3 snappedPoint, ref float bestDist)
        {
            if (surfaceReference == null)
            {
                return;
            }

            if ((snapSettings & UVSnapSettings.GeometryEdges) == UVSnapSettings.None)
            {
                return;
            }

            var localToWorldSpace = surfaceReference.LocalToWorldSpace;
            var subMesh           = surfaceReference.SubMesh;

            Debug.Assert(surfaceReference.surfaceIndex >= 0 && surfaceReference.surfaceIndex < subMesh.Polygons.Length);

            var grid              = UnitySceneExtensions.Grid.defaultGrid;
            var xAxis             = grid.Right;
            var yAxis             = grid.Up;
            var zAxis             = grid.Forward;
            var intersectionPlane = surfaceReference.WorldPlane.Value;

            var snapAxis = Axis.X | Axis.Y | Axis.Z;

            if (Mathf.Abs(Vector3.Dot(xAxis, intersectionPlane.normal)) >= kAlignmentEpsilon)
            {
                snapAxis &= ~Axis.X;
            }
            if (Mathf.Abs(Vector3.Dot(yAxis, intersectionPlane.normal)) >= kAlignmentEpsilon)
            {
                snapAxis &= ~Axis.Y;
            }
            if (Mathf.Abs(Vector3.Dot(zAxis, intersectionPlane.normal)) >= kAlignmentEpsilon)
            {
                snapAxis &= ~Axis.Z;
            }

            var polygons  = subMesh.Polygons;
            var polygon   = polygons[surfaceReference.surfaceIndex];
            var edges     = subMesh.HalfEdges;
            var vertices  = subMesh.Vertices;
            var firstEdge = polygon.firstEdge;
            var lastEdge  = firstEdge + polygon.edgeCount;

            for (int e = firstEdge; e < lastEdge; e++)
            {
                var twinIndex = edges[e].twinIndex;
#if USE_MANAGED_CSG_IMPLEMENTATION
                var polygonIndex = edges[e].polygonIndex;
#else
                // The managed CSG solution will have a polygon index stored for each half-edge
                // the native solution doesn't have this, however, so we need to find the polygon ourselves
                int polygonIndex = -1;
                for (int p = 0; p < polygons.Length; p++)
                {
                    if (twinIndex < polygons[p].firstEdge)
                    {
                        continue;
                    }
                    if (twinIndex >= polygons[p].firstEdge + polygons[p].edgeCount)
                    {
                        continue;
                    }

                    polygonIndex = p;
                    break;
                }

                if (polygonIndex == -1)
                {
                    continue;
                }
#endif

                var surfaceIndex = polygonIndex;    // FIXME: throughout the code we're making assumptions about polygonIndices being the same as surfaceIndices,
                                                    //         this needs to be fixed
                var localPlane = subMesh.Orientations[surfaceIndex].localPlane;
                var worldPlane = localToWorldSpace.TransformPlane(localPlane);

                if ((CurrentSnapSettings & UVSnapSettings.GeometryGrid) != UVSnapSettings.None)
                {
                    var edgeDirection = Vector3.Cross(intersectionPlane.normal, worldPlane.normal);

                    var edgeSnapAxis = snapAxis;
                    if (Mathf.Abs(Vector3.Dot(xAxis, edgeDirection)) >= kAlignmentEpsilon)
                    {
                        edgeSnapAxis &= ~Axis.X;
                    }
                    if (Mathf.Abs(Vector3.Dot(yAxis, edgeDirection)) >= kAlignmentEpsilon)
                    {
                        edgeSnapAxis &= ~Axis.Y;
                    }
                    if (Mathf.Abs(Vector3.Dot(zAxis, edgeDirection)) >= kAlignmentEpsilon)
                    {
                        edgeSnapAxis &= ~Axis.Z;
                    }

                    if (edgeSnapAxis == Axis.None)
                    {
                        continue;
                    }

                    float dist;
                    var   ray = new Ray(snappedPoint, xAxis);
                    if ((edgeSnapAxis & Axis.X) != Axis.None && worldPlane.UnsignedRaycast(ray, out dist))
                    {
                        var planePoint = ray.GetPoint(dist);
                        var abs_dist   = (planePoint - intersectionPoint).magnitude * preferenceFactor;
                        if (abs_dist < bestDist)
                        {
                            bestDist     = abs_dist;
                            snappedPoint = planePoint;
                        }
                    }
                    ray.direction = yAxis;
                    if ((edgeSnapAxis & Axis.Y) != Axis.None && worldPlane.UnsignedRaycast(ray, out dist))
                    {
                        var planePoint = ray.GetPoint(dist);
                        var abs_dist   = (planePoint - intersectionPoint).magnitude * preferenceFactor;
                        if (abs_dist < bestDist)
                        {
                            bestDist     = abs_dist;
                            snappedPoint = planePoint;
                        }
                    }
                    ray.direction = zAxis;
                    if ((edgeSnapAxis & Axis.Z) != Axis.None && worldPlane.UnsignedRaycast(ray, out dist))
                    {
                        var planePoint = ray.GetPoint(dist);
                        var abs_dist   = (planePoint - intersectionPoint).magnitude * preferenceFactor;
                        if (abs_dist < bestDist)
                        {
                            bestDist     = abs_dist;
                            snappedPoint = planePoint;
                        }
                    }
                }
                else
                {
                    var closestPoint = worldPlane.ClosestPointOnPlane(intersectionPoint);
                    var dist         = (closestPoint - intersectionPoint).magnitude * preferenceFactor;
                    if (dist < bestDist)
                    {
                        bestDist     = dist;
                        snappedPoint = closestPoint;
                    }
                }
            }
        }
        static void SnapGridIntersection(UVSnapSettings snapSettings, SurfaceReference surfaceReference, Vector3 intersectionPoint, float preferenceFactor, ref Vector3 snappedPoint, ref float bestDist)
        {
            if ((snapSettings & UVSnapSettings.GeometryGrid) == UVSnapSettings.None)
            {
                return;
            }

            var grid             = UnitySceneExtensions.Grid.defaultGrid;
            var gridSnappedPoint = Snapping.SnapPoint(intersectionPoint, grid);

            var worldPlane = surfaceReference.WorldPlane.Value;

            var xAxis    = grid.Right;
            var yAxis    = grid.Up;
            var zAxis    = grid.Forward;
            var snapAxis = Axis.X | Axis.Y | Axis.Z;

            if (Mathf.Abs(Vector3.Dot(xAxis, worldPlane.normal)) >= kAlignmentEpsilon)
            {
                snapAxis &= ~Axis.X;
            }
            if (Mathf.Abs(Vector3.Dot(yAxis, worldPlane.normal)) >= kAlignmentEpsilon)
            {
                snapAxis &= ~Axis.Y;
            }
            if (Mathf.Abs(Vector3.Dot(zAxis, worldPlane.normal)) >= kAlignmentEpsilon)
            {
                snapAxis &= ~Axis.Z;
            }

            if (Mathf.Abs(worldPlane.GetDistanceToPoint(gridSnappedPoint)) < kDistanceEpsilon)
            {
                bestDist     = (gridSnappedPoint - intersectionPoint).magnitude * preferenceFactor;
                snappedPoint = gridSnappedPoint;
            }
            else
            {
                float dist;
                var   ray = new Ray(gridSnappedPoint, xAxis);
                if ((snapAxis & Axis.X) != Axis.None && worldPlane.UnsignedRaycast(ray, out dist))
                {
                    var planePoint = ray.GetPoint(dist);
                    var abs_dist   = (planePoint - intersectionPoint).magnitude * preferenceFactor;
                    if (abs_dist < bestDist)
                    {
                        bestDist     = abs_dist;
                        snappedPoint = planePoint;
                    }
                }
                ray.direction = yAxis;
                if ((snapAxis & Axis.Y) != Axis.None && worldPlane.UnsignedRaycast(ray, out dist))
                {
                    var planePoint = ray.GetPoint(dist);
                    var abs_dist   = (planePoint - intersectionPoint).magnitude * preferenceFactor;
                    if (abs_dist < bestDist)
                    {
                        bestDist     = abs_dist;
                        snappedPoint = planePoint;
                    }
                }
                ray.direction = zAxis;
                if ((snapAxis & Axis.Z) != Axis.None && worldPlane.UnsignedRaycast(ray, out dist))
                {
                    var planePoint = ray.GetPoint(dist);
                    var abs_dist   = (planePoint - intersectionPoint).magnitude * preferenceFactor;
                    if (abs_dist < bestDist)
                    {
                        bestDist     = abs_dist;
                        snappedPoint = planePoint;
                    }
                }
            }
        }
        private static bool SurfaceRotateTool(SelectionType selectionType, Rect dragArea)
        {
            var id = GUIUtility.GetControlID(kSurfaceRotateHash, FocusType.Keyboard, dragArea);

            if (!SurfaceToolBase(id, selectionType, dragArea))
            {
                return(false);
            }

            bool needRepaint = false;

            if (!IsToolEnabled(id))
            {
                needRepaint          = haveRotateStartAngle;
                haveRotateStartAngle = false;
                pointHasSnapped      = false;
            }

            switch (Event.current.GetTypeForControl(id))
            {
            // TODO: support rotating texture using keyboard?
            case EventType.Repaint:
            {
                if (haveRotateStartAngle)
                {
                    var toWorldVector = worldDragDeltaVector;
                    var magnitude     = toWorldVector.magnitude;
                    toWorldVector /= magnitude;

                    // TODO: need a nicer visualization here, show delta rotation, angles etc.
                    Handles.DrawWireDisc(worldStartPosition, worldProjectionPlane.normal, magnitude);
                    if (haveRotateStartAngle)
                    {
                        var snappedToWorldVector = Quaternion.AngleAxis(rotateAngle, worldDragPlane.normal) * fromWorldVector;
                        Handles.DrawDottedLine(worldStartPosition, worldStartPosition + (fromWorldVector * magnitude), 4.0f);
                        Handles.DrawDottedLine(worldStartPosition, worldStartPosition + (snappedToWorldVector * magnitude), 4.0f);
                    }
                    else
                    {
                        Handles.DrawDottedLine(worldStartPosition, worldStartPosition + (toWorldVector * magnitude), 4.0f);
                    }
                }
                if (IsToolEnabled(id))
                {
                    if (haveRotateStartAngle &&
                        pointHasSnapped)
                    {
                        RenderIntersectionPoint(worldIntersection);
                        RenderVertexBox(worldIntersection);
                    }
                }
                break;
            }

            case EventType.MouseDrag:
            {
                if (!IsToolEnabled(id))
                {
                    break;
                }

                if (StartToolDragging())
                {
                    haveRotateStartAngle = false;
                    pointHasSnapped      = false;
                }

                var toWorldVector = worldDragDeltaVector;
                if (!haveRotateStartAngle)
                {
                    var handleSize     = HandleUtility.GetHandleSize(worldStartPosition);
                    var minDiameterSqr = handleSize * kMinRotateDiameter;
                    // Only start rotating when we've moved the cursor far away enough from the center of rotation
                    if (toWorldVector.sqrMagnitude > minDiameterSqr)
                    {
                        // Switch to rotation mode, we have a center and a start angle to compare with,
                        // from now on, when we move the mouse we change the rotation angle relative to this first angle.
                        haveRotateStartAngle = true;
                        pointHasSnapped      = false;
                        fromWorldVector      = toWorldVector.normalized;
                        rotateAngle          = 0;

                        // We override the snapping settings to only allow snapping against vertices,
                        // we do this only after we have our starting vector, so that when we rotate we're not constantly
                        // snapping against the grid when we really just want to be able to snap against the current rotation step.
                        // On the other hand, we do want to be able to snap against vertices ..
                        toolSnapOverrides = UVSnapSettings.GeometryVertices;
                    }
                }
                else
                {
                    // Get the angle between 'from' and 'to' on the plane we're dragging over
                    rotateAngle = MathExtensions.SignedAngle(fromWorldVector, toWorldVector.normalized, worldDragPlane.normal);

                    // If we snapped against something, ignore angle snapping
                    if (!pointHasSnapped)
                    {
                        rotateAngle = SnapAngle(rotateAngle);
                    }

                    RotateSurfacesInWorldSpace(worldStartPosition, worldDragPlane.normal, -rotateAngle);     // TODO: figure out why this is reversed
                }
                break;
            }
            }
            return(needRepaint);
        }
Example #7
0
        static void SnapSurfaceEdges(UVSnapSettings snapSettings, SurfaceReference surfaceReference, Vector3 intersectionPoint, float preferenceFactor, ref Vector3 snappedPoint, ref float bestDist)
        {
            if (surfaceReference == null)
            {
                return;
            }

            if ((snapSettings & UVSnapSettings.GeometryEdges) == UVSnapSettings.None)
            {
                return;
            }

            var localToWorldSpace = surfaceReference.LocalToWorldSpace;
            var brushMesh         = surfaceReference.BrushMesh;

            if (brushMesh == null)
            {
                return;
            }

            Debug.Assert(surfaceReference.surfaceIndex >= 0 && surfaceReference.surfaceIndex < brushMesh.polygons.Length);

            var grid              = UnitySceneExtensions.Grid.defaultGrid;
            var xAxis             = grid.Right;
            var yAxis             = grid.Up;
            var zAxis             = grid.Forward;
            var intersectionPlane = surfaceReference.WorldPlane.Value;

            var snapAxis = Axis.X | Axis.Y | Axis.Z;

            if (Mathf.Abs(Vector3.Dot(xAxis, intersectionPlane.normal)) >= kAlignmentEpsilon)
            {
                snapAxis &= ~Axis.X;
            }
            if (Mathf.Abs(Vector3.Dot(yAxis, intersectionPlane.normal)) >= kAlignmentEpsilon)
            {
                snapAxis &= ~Axis.Y;
            }
            if (Mathf.Abs(Vector3.Dot(zAxis, intersectionPlane.normal)) >= kAlignmentEpsilon)
            {
                snapAxis &= ~Axis.Z;
            }

            var polygons  = brushMesh.polygons;
            var polygon   = polygons[surfaceReference.surfaceIndex];
            var halfEdges = brushMesh.halfEdges;
            var halfEdgePolygonIndices = brushMesh.halfEdgePolygonIndices;
            var vertices  = brushMesh.vertices;
            var firstEdge = polygon.firstEdge;
            var lastEdge  = firstEdge + polygon.edgeCount;

            for (int e = firstEdge; e < lastEdge; e++)
            {
                var twinIndex    = halfEdges[e].twinIndex;
                var polygonIndex = halfEdgePolygonIndices[e];

                var surfaceIndex = polygonIndex;    // FIXME: throughout the code we're making assumptions about polygonIndices being the same as surfaceIndices,
                                                    //         this needs to be fixed
                var localPlaneVector = brushMesh.surfaces[surfaceIndex].localPlane;
                var localPlane       = new Plane((Vector3)localPlaneVector, localPlaneVector.w);
                var worldPlane       = localToWorldSpace.TransformPlane(localPlane);

                if ((CurrentSnapSettings & UVSnapSettings.GeometryGrid) != UVSnapSettings.None)
                {
                    var edgeDirection = Vector3.Cross(intersectionPlane.normal, worldPlane.normal);

                    var edgeSnapAxis = snapAxis;
                    if (Mathf.Abs(Vector3.Dot(xAxis, edgeDirection)) >= kAlignmentEpsilon)
                    {
                        edgeSnapAxis &= ~Axis.X;
                    }
                    if (Mathf.Abs(Vector3.Dot(yAxis, edgeDirection)) >= kAlignmentEpsilon)
                    {
                        edgeSnapAxis &= ~Axis.Y;
                    }
                    if (Mathf.Abs(Vector3.Dot(zAxis, edgeDirection)) >= kAlignmentEpsilon)
                    {
                        edgeSnapAxis &= ~Axis.Z;
                    }

                    if (edgeSnapAxis == Axis.None)
                    {
                        continue;
                    }

                    float dist;
                    var   ray = new Ray(snappedPoint, xAxis);
                    if ((edgeSnapAxis & Axis.X) != Axis.None && worldPlane.SignedRaycast(ray, out dist))
                    {
                        var planePoint = ray.GetPoint(dist);
                        var abs_dist   = (planePoint - intersectionPoint).magnitude * preferenceFactor;
                        if (abs_dist < bestDist)
                        {
                            bestDist     = abs_dist;
                            snappedPoint = planePoint;
                        }
                    }
                    ray.direction = yAxis;
                    if ((edgeSnapAxis & Axis.Y) != Axis.None && worldPlane.SignedRaycast(ray, out dist))
                    {
                        var planePoint = ray.GetPoint(dist);
                        var abs_dist   = (planePoint - intersectionPoint).magnitude * preferenceFactor;
                        if (abs_dist < bestDist)
                        {
                            bestDist     = abs_dist;
                            snappedPoint = planePoint;
                        }
                    }
                    ray.direction = zAxis;
                    if ((edgeSnapAxis & Axis.Z) != Axis.None && worldPlane.SignedRaycast(ray, out dist))
                    {
                        var planePoint = ray.GetPoint(dist);
                        var abs_dist   = (planePoint - intersectionPoint).magnitude * preferenceFactor;
                        if (abs_dist < bestDist)
                        {
                            bestDist     = abs_dist;
                            snappedPoint = planePoint;
                        }
                    }
                }
                else
                {
                    var closestPoint = worldPlane.ClosestPointOnPlane(intersectionPoint);
                    var dist         = (closestPoint - intersectionPoint).magnitude * preferenceFactor;
                    if (dist < bestDist)
                    {
                        bestDist     = dist;
                        snappedPoint = closestPoint;
                    }
                }
            }
        }