/// <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); } }
internal static void ApplyPrefsSettings(ProBuilderShape proBuilderShape) { proBuilderShape.pivotLocation = (PivotLocation)s_LastPivotLocation.value; proBuilderShape.pivotLocalPosition = s_LastPivotPosition.value; proBuilderShape.size = s_LastSize.value; proBuilderShape.rotation = s_LastRotation.value; }
static void DoOrientationHandles(ProBuilderShape proBuilderShape, bool updatePrefs) { if (GUIUtility.hotControl != 0 && !k_OrientationControlIDs.Contains(GUIUtility.hotControl)) { return; } foreach (var f in faces) { if (f.IsVisible && EditorShapeUtility.PointerIsInFace(f)) { if (DoOrientationHandle(f, proBuilderShape)) { UndoUtility.RecordComponents <Transform, ProBuilderMesh, ProBuilderShape>(proBuilderShape.GetComponents(typeof(Component)), "Rotate Shape"); proBuilderShape.RotateInsideBounds(s_ShapeRotation); ProBuilderEditor.Refresh(); if (updatePrefs) { DrawShapeTool.SaveShapeParams(proBuilderShape); } } } } }
internal static void SaveShapeParams(ProBuilderShape proBuilderShape) { s_LastPivotLocation.value = (int)proBuilderShape.pivotLocation; s_LastPivotPosition.value = proBuilderShape.pivotLocalPosition; s_LastSize.value = proBuilderShape.size; s_LastRotation.value = proBuilderShape.rotation; EditorShapeUtility.SaveParams(proBuilderShape.shape); }
static void ApplyProperties(ProBuilderShape proBuilderShape, Vector3 newCenterPosition, Vector3 newSize) { var bounds = new Bounds(); bounds.center = newCenterPosition; bounds.size = newSize; UndoUtility.RecordComponents <Transform, ProBuilderMesh, ProBuilderShape>(proBuilderShape.GetComponents(typeof(Component)), "Resize Shape"); proBuilderShape.UpdateBounds(bounds); ProBuilderEditor.Refresh(false); }
void DrawShapeGUI() { if (m_BoldCenteredStyle == null) { m_BoldCenteredStyle = new GUIStyle("BoldLabel") { alignment = TextAnchor.MiddleCenter } } ; EditorGUILayout.LabelField(EditorShapeUtility.shapeTypes[s_ActiveShapeIndex.value], m_BoldCenteredStyle, GUILayout.ExpandWidth(true)); if (EditorShapeUtility.s_ResetUserPrefs.value) { ResetPrefs(); } var shape = currentShapeInOverlay.shape; int groupCount = EditorShapeUtility.shapeTypesGUI.Count; for (int i = 0; i < groupCount; i++) { EditorGUI.BeginChangeCheck(); EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); int index = GUILayout.Toolbar(s_ActiveShapeIndex.value - +i * EditorShapeUtility.MaxContentPerGroup, EditorShapeUtility.shapeTypesGUI[i], Styles.command); GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); if (EditorGUI.EndChangeCheck()) { s_ActiveShapeIndex.value = index + i * EditorShapeUtility.MaxContentPerGroup; var type = EditorShapeUtility.availableShapeTypes[s_ActiveShapeIndex]; if (shape.GetType() != type) { if (currentShapeInOverlay == m_LastShapeCreated) { m_LastShapeCreated = null; } UndoUtility.RegisterCompleteObjectUndo(currentShapeInOverlay, "Change Shape"); Selection.activeObject = null; currentShapeInOverlay.SetShape(EditorShapeUtility.CreateShape(type), currentShapeInOverlay.pivotLocation); SetBounds(currentShapeInOverlay.size); ProBuilderEditor.Refresh(); } } } } }
void ResetPrefs() { var type = EditorShapeUtility.availableShapeTypes[s_ActiveShapeIndex]; if (currentShapeInOverlay == m_LastShapeCreated) { m_LastShapeCreated = null; } UndoUtility.RegisterCompleteObjectUndo(currentShapeInOverlay, "Change Shape"); currentShapeInOverlay.SetShape(EditorShapeUtility.CreateShape(type), currentShapeInOverlay.pivotLocation); SetBounds(currentShapeInOverlay.size); ProBuilderEditor.Refresh(); }
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); }
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); } } } }
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); } } } }
public void DrawShapeParametersGUI(DrawShapeTool tool = null) { if (target == null || serializedObject == null) { return; } serializedObject.Update(); var foldoutEnabled = tool == null ? s_foldoutEnabled : DrawShapeTool.s_SettingsEnabled.value; foldoutEnabled = EditorGUILayout.Foldout(foldoutEnabled, m_ShapePropertyLabel, true); if (tool == null) { s_foldoutEnabled = foldoutEnabled; } else { DrawShapeTool.s_SettingsEnabled.value = foldoutEnabled; } if (foldoutEnabled) { EditorGUI.indentLevel++; EditorGUI.BeginChangeCheck(); m_ActiveShapeIndex = HasMultipleShapeTypes ? -1 : Mathf.Max(-1, Array.IndexOf(EditorShapeUtility.availableShapeTypes, m_CurrentShapeType)); m_ActiveShapeIndex = EditorGUILayout.Popup(m_ActiveShapeIndex, EditorShapeUtility.shapeTypes); if (EditorGUI.EndChangeCheck()) { var type = EditorShapeUtility.availableShapeTypes[m_ActiveShapeIndex]; foreach (var comp in targets) { ProBuilderShape proBuilderShape = ((ProBuilderShape)comp); Shape shape = proBuilderShape.shape; if (shape.GetType() != type) { if (tool != null) { DrawShapeTool.s_ActiveShapeIndex.value = m_ActiveShapeIndex; } UndoUtility.RecordComponents <Transform, ProBuilderMesh, ProBuilderShape>(new [] { proBuilderShape }, "Change Shape"); proBuilderShape.SetShape(EditorShapeUtility.CreateShape(type), proBuilderShape.pivotLocation); ProBuilderEditor.Refresh(); } } } if (tool) { EditorGUILayout.PropertyField(m_ShapePivotProperty, k_ShapePivotLabel); } var labelWidth = EditorGUIUtility.labelWidth; var fieldWidth = EditorGUIUtility.fieldWidth; EditorGUIUtility.labelWidth = 30; EditorGUIUtility.fieldWidth = 30; EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(m_ShapeSizeXProperty, k_ShapeSizeXLabel); var is2D = HasMultipleShapeTypes || (m_CurrentShapeType != typeof(Plane) && m_CurrentShapeType != typeof(Sprite)); using (new EditorGUI.DisabledScope(!is2D)) EditorGUILayout.PropertyField(m_ShapeSizeYProperty, k_ShapeSizeYLabel); EditorGUILayout.PropertyField(m_ShapeSizeZProperty, k_ShapeSizeZLabel); EditorGUILayout.EndHorizontal(); EditorGUIUtility.labelWidth = labelWidth; EditorGUIUtility.fieldWidth = fieldWidth; EditorGUI.indentLevel--; } if (!HasMultipleShapeTypes) { EditorGUILayout.PropertyField(m_ShapeProperty, new GUIContent("Shape Properties"), true); } if (serializedObject.ApplyModifiedProperties()) { foreach (var comp in targets) { var shapeComponent = comp as ProBuilderShape; if (shapeComponent.isEditable) { UndoUtility.RecordComponents <Transform, ProBuilderMesh, ProBuilderShape>(shapeComponent.GetComponents(typeof(Component)), "Resize Shape"); shapeComponent.UpdateComponent(); if (tool != null) { tool.SetBounds(shapeComponent.size); DrawShapeTool.SaveShapeParams(shapeComponent); } ProBuilderEditor.Refresh(); } } } GUI.enabled = true; }