Example #1
0
        void SetupInputPlane(Vector2 mousePosition)
        {
            plane = EditorHandleUtility.FindBestPlane(mousePosition);

            var planeNormal = plane.normal;
            var planeCenter = plane.normal * -plane.distance;

            // if hit point on plane is cardinal axis and on grid, snap to grid.
            if (Math.IsCardinalAxis(planeNormal))
            {
                const float epsilon = .00001f;
                bool        offGrid = false;
                Vector3     snapVal = EditorSnapping.activeMoveSnapValue;
                Vector3     center  = Vector3.Scale(ProBuilderSnapping.GetSnappingMaskBasedOnNormalVector(planeNormal), planeCenter);
                for (int i = 0; i < 3; i++)
                {
                    offGrid |= Mathf.Abs(snapVal[i] % center[i]) > epsilon;
                }
                polygon.isOnGrid = !offGrid;
            }
            else
            {
                polygon.isOnGrid = false;
            }
        }
Example #2
0
        /// <summary>
        /// The Editing handles are used to manipulate and resize ProBuilderShapes
        /// These handles are used in 2 tools : EditShapeTool and DrawShapeTool. In this second tool,
        /// these handles allow to modified the last created shape.
        /// </summary>
        /// <param name="proBuilderShape">The Shape on which to attach the handles</param>
        /// <param name="updatePrefs">Parameter used to update the DrawShapeTool when needed</param>
        internal static void DoEditingHandles(ProBuilderShape proBuilderShape, bool updatePrefs = false)
        {
            if (proBuilderShape == null)
            {
                return;
            }

            var scale    = proBuilderShape.transform.lossyScale;
            var position = proBuilderShape.transform.position
                           + Vector3.Scale(proBuilderShape.transform.TransformDirection(proBuilderShape.shapeBox.center), scale);
            var matrix = Matrix4x4.TRS(position, proBuilderShape.transform.rotation, Vector3.one);

            using (new Handles.DrawingScope(matrix))
            {
                EditorShapeUtility.UpdateFaces(proBuilderShape.editionBounds, scale, faces);

                for (int i = 0; i < 4; ++i)
                {
                    k_OrientationControlIDs[i] = GUIUtility.GetControlID(FocusType.Passive);
                }
                for (int i = 0; i < faces.Length; ++i)
                {
                    s_FaceControlIDs[i] = GUIUtility.GetControlID(FocusType.Passive);
                }

                var absSize = Math.Abs(proBuilderShape.editionBounds.size);
                if (absSize.x > Mathf.Epsilon && absSize.y > Mathf.Epsilon && absSize.z > Mathf.Epsilon)
                {
                    DoOrientationHandles(proBuilderShape, updatePrefs);
                }

                DoSizeHandles(proBuilderShape, updatePrefs);
            }
        }
            public override void OnGUI()
            {
                s_Radius.value = EditorGUILayout.FloatField("Radius", s_Radius);
                s_Radius.value = Mathf.Clamp(s_Radius, k_MinShapeDimensions.x, k_MinShapeDimensions.x);

                s_AxisSegments.value = EditorGUILayout.IntField("Number of Sides", s_AxisSegments);
                s_AxisSegments.value = PMath.Clamp(s_AxisSegments, 4, 128);

                s_Height.value = EditorGUILayout.FloatField("Height", s_Height);
                s_Height.value = Mathf.Clamp(s_Height.value, k_MinShapeDimensions.x, k_MaxShapeDimensions.x);

                s_HeightSegments.value = EditorGUILayout.IntField("Height Segments", s_HeightSegments);
                s_HeightSegments.value = UnityEngine.ProBuilder.Math.Clamp(s_HeightSegments, 0, 48);
                s_HeightSegments.value = Mathf.Clamp(s_HeightSegments.value, 0, 128);

                s_Smooth.value = EditorGUILayout.Toggle("Smooth", s_Smooth);

                if (s_AxisSegments % 2 != 0)
                {
                    s_AxisSegments.value++;
                }

                if (s_HeightSegments < 0)
                {
                    s_HeightSegments.value = 0;
                }
            }
Example #4
0
        /// <summary>
        /// Create a shape with the last set <see cref="ShapeEditor"/> parameters.
        /// </summary>
        /// <returns>A reference to the <see cref="ProBuilderMesh"/> of the newly created GameObject.</returns>
        public static ProBuilderMesh CreateActiveShape()
        {
            var res = s_ShapeBuilders[PMath.Clamp(s_CurrentIndex, 0, s_ShapeBuilders.Length - 1)].Build();

            Undo.RegisterCreatedObjectUndo(res.gameObject, "Create Shape");
            EditorUtility.InitObject(res);
            return(res);
        }
Example #5
0
        float GetDragDistance()
        {
            Ray     constraint   = m_DragState.constraint;
            Ray     mouse        = m_SceneCamera.ScreenPointToRay(Input.mousePosition);
            Vector3 nearestPoint = PMath.GetNearestPointRayRay(constraint, mouse);
            float   sign         = System.Math.Sign(Vector3.Dot(nearestPoint - constraint.origin, constraint.direction));

            return(Vector3.Distance(constraint.origin, nearestPoint) * sign);
        }
            public override void OnGUI()
            {
                s_Radius.value       = EditorGUILayout.FloatField("Radius", s_Radius);
                s_Height.value       = EditorGUILayout.FloatField("Height", s_Height);
                s_AxisSegments.value = EditorGUILayout.IntField("Number of Sides", s_AxisSegments);

                s_Radius.value       = Mathf.Clamp(s_Radius.value, k_MinShapeDimensions.x, k_MaxShapeDimensions.x);
                s_Height.value       = Mathf.Clamp(s_Height.value, k_MinShapeDimensions.x, k_MaxShapeDimensions.x);
                s_AxisSegments.value = PMath.Clamp(s_AxisSegments, 3, 64);
            }
Example #7
0
        void SetPolyEditMode(PolyShape.PolyEditMode mode)
        {
            if (polygon == null)
            {
                return;
            }

            PolyShape.PolyEditMode old = polygon.polyEditMode;

            if (mode != old)
            {
                GUIUtility.hotControl = 0;

                // Entering edit mode after the shape has been finalized once before, which means
                // possibly reverting manual changes.  Store undo state so that if this was
                // not intentional user can revert.
                if (old == PolyShape.PolyEditMode.None && polygon.m_Points.Count > 2)
                {
                    if (ProBuilderEditor.instance != null)
                    {
                        ProBuilderEditor.instance.ClearElementSelection();
                    }

                    UndoUtility.RecordComponents <ProBuilderMesh, PolyShape>(polygon.GetComponents(typeof(Component)), "Edit Polygon Shape");
                }

                polygon.polyEditMode = mode;

                // If coming from Path -> Height set the mouse / origin offset
                if (old == PolyShape.PolyEditMode.Path && mode == PolyShape.PolyEditMode.Height && Event.current != null)
                {
                    Vector3 up      = polygon.transform.up;
                    Vector3 origin  = polygon.transform.TransformPoint(Math.Average(polygon.m_Points));
                    Ray     r       = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
                    Vector3 p       = Math.GetNearestPointRayRay(origin, up, r.origin, r.direction);
                    float   extrude = Vector3.Distance(origin, p) * Mathf.Sign(Vector3.Dot(p - origin, up));
                    s_HeightMouseOffset = polygon.extrude - EditorSnapping.MoveSnap(extrude);
                }
                else if (old == PolyShape.PolyEditMode.Path && mode == PolyShape.PolyEditMode.None)
                {
                    var go = polygon.gameObject;
                    EditorApplication.delayCall += () => DestroyImmediate(go);
                    return;
                }

                RebuildPolyShapeMesh(polygon);

                //Dirty the polygon for serialization (fix for transition between prefab and scene mode)
                if (polygon != null)
                {
                    UnityEditor.EditorUtility.SetDirty(polygon);
                }
            }
        }
            public override void OnGUI()
            {
                s_Axis.value = (Axis)EditorGUILayout.EnumPopup("Axis", s_Axis);

                s_Width.value  = EditorGUILayout.FloatField("Width", s_Width);
                s_Height.value = EditorGUILayout.FloatField("Length", s_Height);
                s_Width.value  = Mathf.Clamp(s_Width.value, k_MinShapeDimensions.x, k_MaxShapeDimensions.x);
                s_Height.value = Mathf.Clamp(s_Height.value, k_MinShapeDimensions.x, k_MaxShapeDimensions.x);

                s_WidthSegments.value  = EditorGUILayout.IntField("Width Segments", s_WidthSegments);
                s_HeightSegments.value = EditorGUILayout.IntField("Length Segments", s_HeightSegments);

                s_WidthSegments.value  = PMath.Clamp(s_WidthSegments.value, 0, 512);
                s_HeightSegments.value = PMath.Clamp(s_HeightSegments.value, 0, 512);
            }
            public override void OnGUI()
            {
                s_Radius.value         = EditorGUILayout.FloatField("Radius", s_Radius);
                s_Height.value         = EditorGUILayout.FloatField("Height", s_Height);
                s_Thickness.value      = EditorGUILayout.FloatField("Thickness", s_Thickness);
                s_AxisSegments.value   = EditorGUILayout.IntField("Number of Sides", s_AxisSegments);
                s_HeightSegments.value = EditorGUILayout.IntField("Height Segments", s_HeightSegments);

                s_Radius.value         = Mathf.Clamp(s_Radius.value, k_MinShapeDimensions.x, k_MaxShapeDimensions.x);
                s_Height.value         = Mathf.Clamp(s_Height.value, k_MinShapeDimensions.x, k_MaxShapeDimensions.x);
                s_HeightSegments.value = (int)Mathf.Clamp(s_HeightSegments, 0f, 32f);
                s_Thickness.value      = Mathf.Clamp(s_Thickness, .01f, s_Radius - .01f);
                s_AxisSegments.value   = PMath.Clamp(s_AxisSegments, 3, 64);
                s_HeightSegments.value = PMath.Clamp(s_HeightSegments.value, 0, 128);
            }
Example #10
0
        void BeginDrag()
        {
            if (m_DragState.active)
            {
                return;
            }

            m_DragState.active = true;

            var trs = m_Selection.mesh.transform;

            // The constraint ray is stored in world space
            var origin    = trs.TransformPoint(PMath.Average(m_Selection.mesh.positions, m_Selection.face.indexes));
            var direction = trs.TransformDirection(PMath.Normal(m_Selection.mesh, m_Selection.face));

            m_DragState.constraint = new Ray(origin, direction);
            m_DragState.meshState  = new MeshState(m_Selection.mesh, m_Selection.face.distinctIndexes);
            m_DragState.offset     = GetDragDistance();
        }
            public override void OnGUI()
            {
                s_Steps.value         = (int)Mathf.Max(UI.EditorGUIUtility.FreeSlider("Steps", s_Steps, 2, 64), 2);
                s_Steps.value         = PMath.Clamp(s_Steps, 2, 512);
                s_Sides.value         = EditorGUILayout.Toggle("Build Sides", s_Sides);
                s_Circumference.value = EditorGUILayout.Slider("Curvature", s_Circumference, 0f, 360f);

                Vector3 size = s_Size.value;

                if (s_Circumference > 0f)
                {
                    s_Mirror.value = EditorGUILayout.Toggle("Mirror", s_Mirror);

                    size.x =
                        Mathf.Max(
                            UI.EditorGUIUtility.FreeSlider(
                                new GUIContent("Stair Width", "The width of an individual stair step."), size.x,
                                .01f, 10f), .01f);
                    size.y =
                        Mathf.Max(
                            UI.EditorGUIUtility.FreeSlider(
                                new GUIContent("Stair Height",
                                               "The total height of this staircase.  You may enter any value in the float field."),
                                size.y, .01f, 10f), .01f);
                    size.z =
                        Mathf.Max(
                            UI.EditorGUIUtility.FreeSlider(
                                new GUIContent("Inner Radius", "The distance from the center that stairs begin."),
                                size.z, 0f, 10f), 0f);

                    s_Size.value = size;
                }
                else
                {
                    size.x = UI.EditorGUIUtility.FreeSlider("Width", size.x, 0.01f, 10f);
                    size.y = UI.EditorGUIUtility.FreeSlider("Height", size.y, 0.01f, 10f);
                    size.z = UI.EditorGUIUtility.FreeSlider("Depth", size.z, 0.01f, 10f);
                }

                s_Size.value = PMath.Clamp(size, k_MinShapeDimensions, k_MaxShapeDimensions);
            }
Example #12
0
        /// <summary>
        /// Resize any collider components on this mesh to match the size of the mesh bounds.
        /// </summary>
        /// <param name="mesh">The mesh target to rebuild collider volumes for.</param>
        public static void RebuildColliders(this ProBuilderMesh mesh)
        {
            mesh.mesh.RecalculateBounds();

            var bounds = mesh.mesh.bounds;

            foreach (var collider in mesh.GetComponents <Collider>())
            {
                Type t = collider.GetType();

                if (t == typeof(BoxCollider))
                {
                    ((BoxCollider)collider).center = bounds.center;
                    ((BoxCollider)collider).size   = bounds.size;
                }
                else if (t == typeof(SphereCollider))
                {
                    ((SphereCollider)collider).center = bounds.center;
                    ((SphereCollider)collider).radius = Math.LargestValue(bounds.extents);
                }
                else if (t == typeof(CapsuleCollider))
                {
                    ((CapsuleCollider)collider).center = bounds.center;
                    Vector2 xy = new Vector2(bounds.extents.x, bounds.extents.z);
                    ((CapsuleCollider)collider).radius = Math.LargestValue(xy);
                    ((CapsuleCollider)collider).height = bounds.size.y;
                }
                else if (t == typeof(WheelCollider))
                {
                    ((WheelCollider)collider).center = bounds.center;
                    ((WheelCollider)collider).radius = Math.LargestValue(bounds.extents);
                }
                else if (t == typeof(MeshCollider))
                {
                    ((MeshCollider)collider).sharedMesh = null;
                    ((MeshCollider)collider).sharedMesh = mesh.mesh;
                }
            }
        }
        bool CheckFaceVertexAttributes(ProBuilderMesh mesh, Face face, out InvalidFaceInfo info)
        {
            info = default;
            var positions = mesh.positionsInternal;
            var normals   = mesh.normalsInternal;
            var tangents  = mesh.tangentsInternal;
            var textures  = mesh.texturesInternal;
            var indices   = face.indexesInternal;
            var distinct  = face.distinctIndexesInternal;

            for (int i = 0, c = indices.Length; i < c; i += 3)
            {
                if (Math.TriangleArea(positions[indices[i]], positions[indices[i + 1]], positions[indices[i + 2]]) < float.Epsilon)
                {
                    info.problems += $"Degenerate Triangle {indices[i]} {indices[i+1]} {indices[i+2]}";
                }
            }

            for (int i = 0, c = distinct.Length; i < c; ++i)
            {
                if (normals != null && !Math.IsNumber(normals[i]))
                {
                    info.problems += $"normals [{i}] is NaN";
                }
                if (textures != null && !Math.IsNumber(textures[i]))
                {
                    info.problems += $"uv0 [{i}] is NaN";
                }
                if (tangents != null && !Math.IsNumber(tangents[i]))
                {
                    info.problems += $"tangents [{i}] is NaN";
                }
            }

            info.position = Math.Average(positions, distinct);

            return(!string.IsNullOrEmpty(info.problems));
        }
Example #14
0
        static void DoSizeHandles(ProBuilderShape proBuilderShape, bool updatePrefs)
        {
            int faceCount = s_Faces.Length;

            var evt = Event.current;

            var is2D = proBuilderShape.shape is Plane || proBuilderShape.shape is Sprite;

            for (int i = 0; i < faceCount; i++)
            {
                var face = faces[i];
                if (is2D && !face.IsValid)
                {
                    continue;
                }

                if (Event.current.type == EventType.Repaint)
                {
                    Color color = k_BoundsHandleColor;
                    color.a *= face.IsVisible ? 1f : 0.5f;
                    using (new Handles.DrawingScope(color))
                    {
                        int pointsCount = face.Points.Length;
                        for (int k = 0; k < pointsCount; k++)
                        {
                            Handles.DrawLine(face.Points[k], face.Points[(k + 1) % pointsCount]);
                        }
                    }
                }

                if (DoFaceSizeHandle(face, s_FaceControlIDs[i]))
                {
                    if (!s_SizeManipulationInit)
                    {
                        s_StartCenter          = proBuilderShape.transform.position + proBuilderShape.transform.TransformVector(proBuilderShape.shapeBox.center);
                        s_StartScale           = proBuilderShape.transform.lossyScale;
                        s_StartScaleInverse    = new Vector3(1f / Mathf.Abs(s_StartScale.x), 1f / Mathf.Abs(s_StartScale.y), 1f / Mathf.Abs(s_StartScale.z));
                        s_StartPositionLocal   = face.CenterPosition;
                        s_StartPositionGlobal  = proBuilderShape.transform.TransformPoint(Vector3.Scale(face.CenterPosition, s_StartScale));
                        s_StartSize            = proBuilderShape.size;
                        s_SizeManipulationInit = true;
                        s_Scaling = Vector3.Scale(face.Normal, Math.Sign(s_StartSize));
                    }

                    var targetSize = s_StartSize;
                    if (Math.IsCardinalAxis(proBuilderShape.transform.up) &&
                        EditorSnapSettings.gridSnapEnabled &&
                        !EditorSnapSettings.incrementalSnapActive &&
                        !evt.alt)
                    {
                        var faceDelta    = (s_SizeDelta * s_Faces[i].Normal);
                        var facePosition = s_StartPositionGlobal + faceDelta;
                        facePosition = ProBuilderSnapping.Snap(facePosition, EditorSnapping.activeMoveSnapValue);
                        targetSize  += Vector3.Scale((facePosition - s_StartPositionGlobal), s_Scaling);
                    }
                    else
                    {
                        //Should we expand on the 2 sides?
                        var modifier = evt.alt ? 2f : 1f;
                        var delta    = modifier * (s_SizeDelta * s_Faces[i].Normal);
                        delta.Scale(s_Scaling);
                        delta.Scale(s_StartScaleInverse);

                        targetSize += delta;
                        var snap = EditorSnapSettings.incrementalSnapActive
                            ? Vector3.Scale(EditorSnapping.activeMoveSnapValue, Math.Abs(face.Normal))
                            : Vector3.zero;

                        targetSize = ProBuilderSnapping.Snap(targetSize, snap);
                    }

                    var center = Vector3.zero;
                    if (!evt.alt)
                    {
                        center = Vector3.Scale((targetSize - s_StartSize) / 2f, s_Scaling);
                        center = Vector3.Scale(center, Math.Sign(s_StartScale));
                        center = proBuilderShape.transform.TransformVector(center);
                    }

                    ApplyProperties(proBuilderShape, s_StartCenter + center, targetSize);

                    if (updatePrefs)
                    {
                        DrawShapeTool.SaveShapeParams(proBuilderShape);
                    }
                }
            }
        }
Example #15
0
        void DoExistingPointsGUI()
        {
            Transform trs = polygon.transform;
            int       len = polygon.m_Points.Count;

            Vector3 up      = trs.up;
            Vector3 right   = trs.right;
            Vector3 forward = trs.forward;
            Vector3 center  = Vector3.zero;

            Event evt = Event.current;

            bool used = evt.type == EventType.Used;

            if (!used &&
                (evt.type == EventType.MouseDown &&
                 evt.button == 0 &&
                 !EditorHandleUtility.IsAppendModifier(evt.modifiers)))
            {
                m_SelectedIndex = -1;
            }

            if (evt.type == EventType.Repaint && polygon.polyEditMode == PolyShape.PolyEditMode.Path)
            {
                Vector3 currentPos = polygon.transform.TransformPoint(m_CurrentPosition);
                Handles.color = k_HandleColor;
                Handles.DotHandleCap(-1, currentPos, Quaternion.identity, HandleUtility.GetHandleSize(currentPos) * k_HandleSize, evt.type);
                Handles.color = Color.white;
            }

            if (polygon.polyEditMode == PolyShape.PolyEditMode.Height)
            {
                if (!used && evt.type == EventType.MouseUp && evt.button == 0 && !EditorHandleUtility.IsAppendModifier(evt.modifiers))
                {
                    evt.Use();
                    SetPolyEditMode(PolyShape.PolyEditMode.Edit);
                }

                bool sceneInUse = EditorHandleUtility.SceneViewInUse(evt);
                Ray  r          = HandleUtility.GUIPointToWorldRay(evt.mousePosition);

                Vector3 origin  = polygon.transform.TransformPoint(Math.Average(polygon.m_Points));
                float   extrude = polygon.extrude;

                if (evt.type == EventType.MouseMove && !sceneInUse)
                {
                    Vector3 p = Math.GetNearestPointRayRay(origin, up, r.origin, r.direction);
                    extrude = EditorSnapping.MoveSnap(s_HeightMouseOffset + Vector3.Distance(origin, p) * Mathf.Sign(Vector3.Dot(p - origin, up)));
                }

                Vector3 extrudePoint = origin + (extrude * up);

                if (m_DrawHeightHandles)
                {
                    Handles.color = k_HandleColor;
                    Handles.DotHandleCap(-1, origin, Quaternion.identity, HandleUtility.GetHandleSize(origin) * k_HandleSize, evt.type);
                    Handles.color = k_HandleColorGreen;
                    Handles.DrawLine(origin, extrudePoint);
                    Handles.DotHandleCap(-1, extrudePoint, Quaternion.identity, HandleUtility.GetHandleSize(extrudePoint) * k_HandleSize, evt.type);
                    Handles.color = Color.white;
                }

                if (!sceneInUse && polygon.extrude != extrude)
                {
                    OnBeginVertexMovement();
                    polygon.extrude = extrude;
                    RebuildPolyShapeMesh(false);
                }
            }
            else
            {
                // vertex dots
                for (int ii = 0; ii < len; ii++)
                {
                    Vector3 point = trs.TransformPoint(polygon.m_Points[ii]);

                    center.x += point.x;
                    center.y += point.y;
                    center.z += point.z;

                    float size = HandleUtility.GetHandleSize(point) * k_HandleSize;

                    Handles.color = ii == m_SelectedIndex ? k_HandleSelectedColor : k_HandleColor;

                    EditorGUI.BeginChangeCheck();

                    point = Handles.Slider2D(point, up, right, forward, size, Handles.DotHandleCap, Vector2.zero, true);

                    if (EditorGUI.EndChangeCheck())
                    {
                        UndoUtility.RecordObject(polygon, "Move Polygon Shape Point");
                        polygon.m_Points[ii] = GetPointInLocalSpace(point);
                        OnBeginVertexMovement();
                        RebuildPolyShapeMesh(false);
                    }

                    // "clicked" a button
                    if (!used && evt.type == EventType.Used)
                    {
                        if (ii == 0 && polygon.m_Points.Count > 2 && polygon.polyEditMode == PolyShape.PolyEditMode.Path)
                        {
                            m_NextMouseUpAdvancesMode = true;
                            return;
                        }
                        else
                        {
                            used            = true;
                            m_SelectedIndex = ii;
                        }
                    }
                }

                Handles.color = Color.white;

                // height setting
                if (polygon.polyEditMode != PolyShape.PolyEditMode.Path && polygon.m_Points.Count > 2)
                {
                    center.x /= (float)len;
                    center.y /= (float)len;
                    center.z /= (float)len;

                    Vector3 extrude = center + (up * polygon.extrude);
                    m_DistanceFromHeightHandle = Vector2.Distance(HandleUtility.WorldToGUIPoint(extrude), evt.mousePosition);

                    EditorGUI.BeginChangeCheck();

                    if (m_DrawHeightHandles)
                    {
                        Handles.color = k_HandleColor;
                        Handles.DotHandleCap(-1, center, Quaternion.identity, HandleUtility.GetHandleSize(center) * k_HandleSize, evt.type);
                        Handles.DrawLine(center, extrude);
                        Handles.color = k_HandleColorGreen;
                        extrude       = Handles.Slider(extrude, up, HandleUtility.GetHandleSize(extrude) * k_HandleSize, Handles.DotHandleCap, 0f);
                        Handles.color = Color.white;
                    }

                    if (EditorGUI.EndChangeCheck())
                    {
                        UndoUtility.RecordObject(polygon, "Set Polygon Shape Height");
                        polygon.extrude = EditorSnapping.MoveSnap(Vector3.Distance(extrude, center) * Mathf.Sign(Vector3.Dot(up, extrude - center)));
                        OnBeginVertexMovement();
                        RebuildPolyShapeMesh(false);
                    }
                }
            }
        }
Example #16
0
        void DoPointPlacement()
        {
            Event     evt       = Event.current;
            EventType eventType = evt.type;

            if (m_PlacingPoint)
            {
                Ray ray = HandleUtility.GUIPointToWorldRay(evt.mousePosition);

                if (eventType == EventType.MouseDrag)
                {
                    float hitDistance = Mathf.Infinity;

                    if (plane.Raycast(ray, out hitDistance))
                    {
                        evt.Use();
                        polygon.m_Points[m_SelectedIndex] = GetPointInLocalSpace(ray.GetPoint(hitDistance));
                        RebuildPolyShapeMesh(false);
                        SceneView.RepaintAll();
                    }
                }

                if (eventType == EventType.MouseUp ||
                    eventType == EventType.Ignore ||
                    eventType == EventType.KeyDown ||
                    eventType == EventType.KeyUp)
                {
                    evt.Use();
                    m_PlacingPoint  = false;
                    m_SelectedIndex = -1;
                    SceneView.RepaintAll();
                }
            }
            else if (polygon.polyEditMode == PolyShape.PolyEditMode.Path)
            {
                if (eventType == EventType.MouseDown && HandleUtility.nearestControl == m_ControlId)
                {
                    if (polygon.m_Points.Count < 1)
                    {
                        SetupInputPlane(evt.mousePosition);
                    }

                    float hitDistance = Mathf.Infinity;

                    Ray ray = HandleUtility.GUIPointToWorldRay(evt.mousePosition);

                    if (plane.Raycast(ray, out hitDistance))
                    {
                        UndoUtility.RecordObject(polygon, "Add Polygon Shape Point");

                        Vector3 hit = ray.GetPoint(hitDistance);

                        if (polygon.m_Points.Count < 1)
                        {
                            // this monstrosity exists so that grid and incremental snap work when possible, and
                            // incremental is enabled when grid is not available.
                            polygon.transform.position = m_Polygon.isOnGrid
                                ? EditorSnapping.MoveSnap(hit)
                                : EditorSnapping.snapMode == SnapMode.Relative
                                    ? ProBuilderSnapping.Snap(hit, EditorSnapping.incrementalSnapMoveValue)
                                    : hit;

                            Vector3 cameraFacingPlaneNormal = plane.normal;
                            if (Vector3.Dot(cameraFacingPlaneNormal, SceneView.lastActiveSceneView.camera.transform.forward) > 0f)
                            {
                                cameraFacingPlaneNormal *= -1;
                            }

                            polygon.transform.rotation = Quaternion.LookRotation(cameraFacingPlaneNormal) * Quaternion.Euler(new Vector3(90f, 0f, 0f));
                        }

                        Vector3 point = GetPointInLocalSpace(hit);

                        if (polygon.m_Points.Count > 2 && Math.Approx3(polygon.m_Points[0], point))
                        {
                            m_NextMouseUpAdvancesMode = true;
                            return;
                        }

                        polygon.m_Points.Add(point);

                        m_PlacingPoint  = true;
                        m_SelectedIndex = polygon.m_Points.Count - 1;
                        RebuildPolyShapeMesh(polygon);

                        evt.Use();
                    }
                }
                else
                {
                    float hitDistance = Mathf.Infinity;
                    Ray   ray         = HandleUtility.GUIPointToWorldRay(evt.mousePosition);

                    if (plane.Raycast(ray, out hitDistance))
                    {
                        Vector3 hit = ray.GetPoint(hitDistance);
                        m_CurrentPosition = GetPointInLocalSpace(hit);
                    }
                }
            }
            else if (polygon.polyEditMode == PolyShape.PolyEditMode.Edit)
            {
                if (polygon.m_Points.Count < 3)
                {
                    SetPolyEditMode(PolyShape.PolyEditMode.Path);
                    return;
                }

                if (m_DistanceFromHeightHandle > PreferenceKeys.k_MaxPointDistanceFromControl)
                {
                    // point insertion
                    Vector2 mouse       = evt.mousePosition;
                    Ray     ray         = HandleUtility.GUIPointToWorldRay(mouse);
                    float   hitDistance = Mathf.Infinity;
                    if (plane.Raycast(ray, out hitDistance))
                    {
                        Vector3 hit   = ray.GetPoint(hitDistance);
                        Vector3 point = GetPointInLocalSpace(hit);

                        int polyCount = polygon.m_Points.Count;

                        float   distToLineInGUI;
                        int     index;
                        Vector3 pInGUI = EditorHandleUtility.ClosestPointToPolyLine(polygon.m_Points, out index, out distToLineInGUI, true, polygon.transform);

                        Vector3 aToPoint = point - polygon.m_Points[index - 1];
                        Vector3 aToB     = polygon.m_Points[index % polyCount] - polygon.m_Points[index - 1];

                        float   ratio = Vector3.Dot(aToPoint, aToB.normalized) / aToB.magnitude;
                        Vector3 wp    = Vector3.Lerp(polygon.m_Points[index - 1], polygon.m_Points[index % polyCount], ratio);
                        wp = polygon.transform.TransformPoint(wp);

                        Vector2 aInGUI           = HandleUtility.WorldToGUIPoint(polygon.transform.TransformPoint(polygon.m_Points[index - 1]));
                        Vector2 bInGUI           = HandleUtility.WorldToGUIPoint(polygon.transform.TransformPoint(polygon.m_Points[index % polyCount]));
                        float   distanceToVertex = Mathf.Min(Vector2.Distance(mouse, aInGUI), Vector2.Distance(mouse, bInGUI));

                        if (distanceToVertex > PreferenceKeys.k_MaxPointDistanceFromControl && distToLineInGUI < PreferenceKeys.k_MaxPointDistanceFromControl)
                        {
                            m_MouseCursor = MouseCursor.ArrowPlus;

                            if (evt.type == EventType.Repaint)
                            {
                                Handles.color = Color.green;
                                Handles.DotHandleCap(-1, wp, Quaternion.identity,
                                                     HandleUtility.GetHandleSize(wp) * k_HandleSize, evt.type);
                            }

                            if (evt.type == EventType.MouseDown && HandleUtility.nearestControl == m_ControlId)
                            {
                                evt.Use();

                                UndoUtility.RecordObject(polygon, "Insert Point");
                                polygon.m_Points.Insert(index, point);
                                m_SelectedIndex = index;
                                m_PlacingPoint  = true;
                                RebuildPolyShapeMesh(true);
                                OnBeginVertexMovement();
                            }

                            Handles.color = Color.white;
                        }

                        if (evt.type != EventType.Repaint)
                        {
                            SceneView.RepaintAll();
                        }
                    }
                }
            }
        }
Example #17
0
        static bool DoOrientationHandle(FaceData face, ProBuilderShape proBuilderShape)
        {
            Event evt        = Event.current;
            bool  hasRotated = false;

            switch (evt.type)
            {
            case EventType.MouseDown:
                if (k_OrientationControlIDs.Contains(HandleUtility.nearestControl) && evt.button == 0)
                {
                    s_CurrentId           = HandleUtility.nearestControl;
                    GUIUtility.hotControl = s_CurrentId;
                    evt.Use();
                }
                break;

            case EventType.MouseUp:
                if (k_OrientationControlIDs.Contains(HandleUtility.nearestControl) && evt.button == 0)
                {
                    GUIUtility.hotControl = 0;
                    evt.Use();
                    if (s_CurrentId == HandleUtility.nearestControl)
                    {
                        //Execute rotation
                        Vector3 targetedNormal = Vector3.zero;
                        for (int i = 0; i < k_OrientationControlIDs.Length; i++)
                        {
                            if (k_OrientationControlIDs[i] == s_CurrentId)
                            {
                                targetedNormal = (s_ArrowsLines[i][1] - face.CenterPosition).normalized;
                                break;
                            }
                        }

                        var currentNormal = face.Normal;
                        currentNormal.Scale(Math.Sign(proBuilderShape.size));
                        targetedNormal.Scale(Math.Sign(proBuilderShape.size));
                        Vector3 rotationAxis = Vector3.Cross(currentNormal, targetedNormal);
                        var     angle        = Vector3.SignedAngle(currentNormal, targetedNormal, rotationAxis);
                        s_ShapeRotation = Quaternion.AngleAxis(angle, rotationAxis);
                        s_CurrentAngle  = (s_CurrentAngle + angle) % 360;

                        hasRotated = true;
                    }
                    s_CurrentId = -1;
                }
                break;

            case EventType.Layout:
                for (int i = 0; i < 4; i++)
                {
                    var   rectPos = 0.8f * s_ArrowsLines[i][1] + 0.2f * face.CenterPosition;
                    float dist    = HandleUtility.DistanceToRectangle(rectPos,
                                                                      Quaternion.LookRotation(face.Normal),
                                                                      HandleUtility.GetHandleSize(face.CenterPosition) * s_DefaultMidpointSquareSize / 2f);
                    HandleUtility.AddControl(k_OrientationControlIDs[i], dist);
                }
                break;

            case EventType.Repaint:
                if (s_CurrentArrowHovered != HandleUtility.nearestControl)
                {
                    s_CurrentAngle = 0f;
                }

                int pointsCount = face.Points.Length;
                s_CurrentArrowHovered = -1;
                for (int i = 0; i < pointsCount; i++)
                {
                    var rectHandleSize = HandleUtility.GetHandleSize(face.CenterPosition) * s_DefaultMidpointSquareSize;

                    var sideDirection  = (face.Points[(i + 1) % pointsCount] - face.Points[i]).normalized;
                    var arrowDirection = Vector3.Cross(face.Normal.normalized, sideDirection).normalized;

                    var topDirection = 2.5f * rectHandleSize * arrowDirection;
                    var top          = face.CenterPosition + topDirection;
                    var A            = topDirection.magnitude;
                    var a            = 0.33f * Mathf.Sqrt(2f * A * A);
                    var h            = 0.5f * Mathf.Sqrt(2f * a * a);
                    s_ArrowsLines[i][0] = top - (h * arrowDirection + h * sideDirection);
                    s_ArrowsLines[i][1] = top;
                    s_ArrowsLines[i][2] = top - (h * arrowDirection - h * sideDirection);

                    bool selected = HandleUtility.nearestControl == k_OrientationControlIDs[i];

                    Color color = selected
                               ? EditorHandleDrawing.edgeSelectedColor
                               : k_BoundsHandleColor;
                    color.a = 1.0f;

                    using (new Handles.DrawingScope(color))
                    {
                        Handles.DrawAAPolyLine(5f, s_ArrowsLines[i]);
                        if (selected)
                        {
                            EditorGUIUtility.AddCursorRect(new Rect(0, 0, Screen.width, Screen.height), MouseCursor.RotateArrow);
                            s_CurrentArrowHovered = HandleUtility.nearestControl;
                            Handles.DrawAAPolyLine(3f,
                                                   new Vector3[]
                            {
                                Vector3.Scale(proBuilderShape.rotation * Vector3.up, proBuilderShape.size / 2f),
                                Vector3.zero,
                                Vector3.Scale(proBuilderShape.rotation * Vector3.forward, proBuilderShape.size / 2f)
                            });
                        }
                    }
                }
                break;

            case EventType.MouseDrag:
                if (k_OrientationControlIDs.Contains(s_CurrentId) && HandleUtility.nearestControl != s_CurrentId)
                {
                    GUIUtility.hotControl = 0;
                    s_CurrentId           = -1;
                }
                break;
            }
            return(hasRotated);
        }
        public override ShapeState DoState(Event evt)
        {
            if (evt.type == EventType.KeyDown)
            {
                switch (evt.keyCode)
                {
                case KeyCode.Escape:
                    ToolManager.RestorePreviousTool();
                    break;
                }
            }

            if (tool.m_LastShapeCreated != null)
            {
                EditShapeTool.DoEditingHandles(tool.m_LastShapeCreated, true);
            }

            if (evt.isMouse && HandleUtility.nearestControl == tool.controlID)
            {
                var res = EditorHandleUtility.FindBestPlaneAndBitangent(evt.mousePosition);

                Ray   ray = HandleUtility.GUIPointToWorldRay(evt.mousePosition);
                float hit;

                if (res.item1.Raycast(ray, out hit))
                {
                    //Plane init
                    tool.m_Plane        = res.item1;
                    tool.m_PlaneForward = res.item2;
                    tool.m_PlaneRight   = Vector3.Cross(tool.m_Plane.normal, tool.m_PlaneForward);

                    var planeNormal = tool.m_Plane.normal;
                    var planeCenter = tool.m_Plane.normal * -tool.m_Plane.distance;
                    // if hit point on plane is cardinal axis and on grid, snap to grid.
                    if (Math.IsCardinalAxis(planeNormal))
                    {
                        const float epsilon = .00001f;
                        bool        offGrid = false;
                        Vector3     snapVal = EditorSnapping.activeMoveSnapValue;
                        Vector3     center  =
                            Vector3.Scale(ProBuilderSnapping.GetSnappingMaskBasedOnNormalVector(planeNormal),
                                          planeCenter);
                        for (int i = 0; i < 3; i++)
                        {
                            offGrid |= Mathf.Abs(snapVal[i] % center[i]) > epsilon;
                        }
                        tool.m_IsOnGrid = !offGrid;
                    }
                    else
                    {
                        tool.m_IsOnGrid = false;
                    }

                    m_HitPosition = tool.GetPoint(ray.GetPoint(hit));

                    //Click has been done => Define a plane for the tool
                    if (evt.type == EventType.MouseDown)
                    {
                        //BB init
                        tool.m_BB_Origin         = m_HitPosition;
                        tool.m_BB_HeightCorner   = tool.m_BB_Origin;
                        tool.m_BB_OppositeCorner = tool.m_BB_Origin;

                        return(NextState());
                    }
                }
                else
                {
                    m_HitPosition = Vector3.negativeInfinity;
                }
            }

            if (GUIUtility.hotControl == 0 && evt.shift && !(evt.control || evt.command))
            {
                tool.DuplicatePreview(m_HitPosition);
            }
            else if (tool.m_DuplicateGO != null)
            {
                Object.DestroyImmediate(tool.m_DuplicateGO);
            }

            // Repaint to visualize the placement preview dot
            if (evt.type == EventType.MouseMove && HandleUtility.nearestControl == tool.controlID)
            {
                HandleUtility.Repaint();
            }

            if (evt.type == EventType.Repaint)
            {
                if (GUIUtility.hotControl == 0 && HandleUtility.nearestControl == tool.controlID)
                {
                    using (new Handles.DrawingScope(EditorHandleDrawing.vertexSelectedColor))
                    {
                        Handles.DotHandleCap(-1, m_HitPosition, Quaternion.identity,
                                             HandleUtility.GetHandleSize(m_HitPosition) * 0.05f, EventType.Repaint);
                    }
                }

                if (GUIUtility.hotControl == 0 && evt.shift && !(evt.control || evt.command))
                {
                    tool.DrawBoundingBox(false);
                }
            }

            return(this);
        }
Example #19
0
 static ShapeBuilder GetActiveShapeBuilder()
 {
     return(s_ShapeBuilders[PMath.Clamp(s_CurrentIndex, 0, s_ShapeBuilders.Length - 1)]);
 }
        static void DoSizeHandles(ProBuilderShape proBuilderShape, bool updatePrefs)
        {
            int faceCount = s_Faces.Length;

            var evt = Event.current;

            var is2D = proBuilderShape.shape is Plane || proBuilderShape.shape is Sprite;

            for (int i = 0; i < faceCount; i++)
            {
                var face = faces[i];
                if (is2D && !face.IsValid)
                {
                    continue;
                }

                if (Event.current.type == EventType.Repaint)
                {
                    Color color = k_BoundsHandleColor;
                    color.a *= face.IsVisible ? 1f : 0.5f;
                    using (new Handles.DrawingScope(color))
                    {
                        int pointsCount = face.Points.Length;
                        for (int k = 0; k < pointsCount; k++)
                        {
                            Handles.DrawLine(face.Points[k], face.Points[(k + 1) % pointsCount]);
                        }
                    }
                }

                if (DoFaceSizeHandle(face))
                {
                    float modifier = 1f;
                    if (evt.alt)
                    {
                        modifier = 2f;
                    }

                    if (!s_SizeManipulationInit)
                    {
                        s_StartCenter          = proBuilderShape.transform.position + proBuilderShape.transform.TransformVector(proBuilderShape.shapeBox.center);
                        s_StartPosition        = face.CenterPosition;
                        s_StartSize            = proBuilderShape.size;
                        s_SizeManipulationInit = true;

                        s_Scaling = Vector3.Scale(face.Normal, Math.Sign(s_StartSize));
                    }

                    var targetDelta = modifier * (s_TargetSize - s_StartPosition);
                    targetDelta.Scale(s_Scaling);

                    var targetSize = s_StartSize + targetDelta;

                    var snap = Math.IsCardinalAxis(proBuilderShape.transform.up) && EditorSnapSettings.gridSnapEnabled ?
                               EditorSnapping.activeMoveSnapValue :
                               Vector3.zero;
                    targetSize = ProBuilderSnapping.Snap(targetSize, snap);

                    var center = Vector3.zero;
                    if (!evt.alt)
                    {
                        center = Vector3.Scale((targetSize - s_StartSize) / 2f, s_Scaling);
                        center = Vector3.Scale(center, Math.Sign(proBuilderShape.transform.lossyScale));
                        center = proBuilderShape.transform.TransformVector(center);
                    }

                    ApplyProperties(proBuilderShape, s_StartCenter + center, targetSize);

                    if (updatePrefs)
                    {
                        DrawShapeTool.SaveShapeParams(proBuilderShape);
                    }
                }
            }
        }