// ============================================= Curve related //this is very slow public static void Split(BGCurvePoint @from, BGCurvePoint to, int parts, Action <Vector3, Vector3> action) { var noControls = @from.ControlType == BGCurvePoint.ControlTypeEnum.Absent && to.ControlType == BGCurvePoint.ControlTypeEnum.Absent; if (noControls) { action(@from.PositionWorld, to.PositionWorld); } else { var fromPos = @from.PositionWorld; var toPos = to.PositionWorld; var control1 = @from.ControlSecondWorld; var control2 = to.ControlFirstWorld; var bothControls = @from.ControlType != BGCurvePoint.ControlTypeEnum.Absent && to.ControlType != BGCurvePoint.ControlTypeEnum.Absent; if (!bothControls && @from.ControlType == BGCurvePoint.ControlTypeEnum.Absent) { control1 = control2; } var prev = fromPos; for (var i = 1; i < parts + 1; i++) { var ratio = i / (float)parts; var currentPosition = bothControls ? BGCurveFormulas.BezierCubic(ratio, fromPos, control1, control2, toPos) : BGCurveFormulas.BezierQuadratic(ratio, fromPos, control1, toPos); action(prev, currentPosition); prev = currentPosition; } } }
/* * public static Vector3 CalculateTangent(BGCurvePoint point, float precision) * { * var curve = point.Curve; * * //not enough points * if (curve.PointsCount < 2) return Vector3.zero; * * var myIndex = curve.IndexOf(point); * * //have no idea why it can happen * if (myIndex < 0) return Vector3.zero; * * //prev point * BGCurvePoint prev = null; * if (myIndex != 0 || curve.Closed) * { * prev = myIndex == 0 ? curve[curve.PointsCount - 1] : curve[myIndex - 1]; * } * * //next point * BGCurvePoint next = null; * if (myIndex != curve.PointsCount - 1 || curve.Closed) * { * next = myIndex == curve.PointsCount - 1 ? curve[0] : curve[myIndex + 1]; * } * return CalculateTangent(point, prev, next, precision); * } */ public static float CalculateDistance(BGCurvePoint from, BGCurvePoint to, int parts) { var distance = 0f; Split(@from, to, parts, (fromPos, toPos) => distance += Vector3.Distance(fromPos, toPos)); return(distance); }
private static BGCurvePoint CreatePointBetween(BGCurve curve, BGCurvePoint previousPoint, BGCurvePoint nextPoint, int parts, BGCurvePoint.ControlTypeEnum controlType) { var newPos = BGEditorUtility.CalculatePosition(previousPoint, nextPoint, .5f); var tangent = BGEditorUtility.CalculateTangent(previousPoint, nextPoint, .5f); var scaledTangent = tangent * DistanceToTangentMultiplier * BGEditorUtility.CalculateDistance(previousPoint, nextPoint, parts); return(curve.CreatePointFromLocalPosition(curve.ToLocal(newPos), controlType, curve.ToLocalDirection(-scaledTangent), curve.ToLocalDirection(scaledTangent))); }
//mask disabled field with red texture private void MaskFieldFor2D(BGCurvePoint point) { var lastRect = GUILayoutUtility.GetLastRect(); var twoLiner = lastRect.height > 18; if (twoLiner) { //I have no idea how to calculate it (bruteforce) var offset = (EditorGUIUtility.labelWidth / lastRect.width) * 50f; var oneFieldWidth = (lastRect.width - offset) / 3; var rect = new Rect(lastRect) { x = lastRect.x + offset, y = lastRect.y + 16, height = 16, width = oneFieldWidth }; switch (point.Curve.Mode2D) { case BGCurve.Mode2DEnum.XY: rect.x += oneFieldWidth * 2; break; case BGCurve.Mode2DEnum.XZ: rect.x += oneFieldWidth; break; case BGCurve.Mode2DEnum.YZ: break; } GUI.DrawTexture(rect, maskTexture); } else { var rect = new Rect(lastRect) { width = (lastRect.width - EditorGUIUtility.labelWidth) / 3f }; switch (point.Curve.Mode2D) { case BGCurve.Mode2DEnum.XY: rect.x = lastRect.x + EditorGUIUtility.labelWidth + rect.width * 2; break; case BGCurve.Mode2DEnum.XZ: rect.x = lastRect.x + EditorGUIUtility.labelWidth + rect.width; break; case BGCurve.Mode2DEnum.YZ: rect.x = lastRect.x + EditorGUIUtility.labelWidth; break; } GUI.DrawTexture(rect, maskTexture); } }
public void On(BGCurvePoint point, int index) { PointIndex = index; this.point = point; On(point.PositionWorld); Get(0).Current = point.ControlType == BGCurvePoint.ControlTypeEnum.Absent; Get(1).Current = point.ControlType == BGCurvePoint.ControlTypeEnum.BezierSymmetrical; Get(2).Current = point.ControlType == BGCurvePoint.ControlTypeEnum.BezierIndependant; }
public bool Remove(BGCurvePoint point) { if (!Contains(point)) { return(false); } Changed = true; points.Remove(point); return(true); }
protected override void AdditionalPreview(BGCurvePoint newPoint) { var curve = overlay.Editor.Curve; if (!curve.Mode2DOn) { return; } Handles.DrawLine(lastPosition, newPoint.PositionWorld); }
public bool Add(BGCurvePoint point) { if (Contains(point)) { return(false); } Changed = true; points.Add(point); return(true); }
//if we selecting or removing selection public void GroupSelection(BGCurvePoint point) { if (groupSelectionIsSelecting) { Add(point); } else { Remove(point); } }
/// <summary>Tangent in World coordinates </summary> public static Vector3 CalculateTangent(BGCurvePoint point, BGCurvePoint previous, BGCurvePoint next, float precision) { var prevTangent = previous != null?CalculateTangent(previous, point, 1 - precision) : Vector3.zero; var nextTangent = next != null?CalculateTangent(point, next, precision) : Vector3.zero; var tangent = (previous != null && next != null) ? Vector3.Lerp(prevTangent, nextTangent, .5f) : next == null ? prevTangent : nextTangent; return(tangent.normalized); }
/// <summary>Tangent in World coordinates </summary> public static Vector3 CalculateTangent(BGCurvePoint @from, BGCurvePoint to, float t) { if (@from.ControlType == BGCurvePoint.ControlTypeEnum.Absent && to.ControlType == BGCurvePoint.ControlTypeEnum.Absent) { return((to.PositionWorld - @from.PositionWorld).normalized); } if (@from.ControlType != BGCurvePoint.ControlTypeEnum.Absent && to.ControlType != BGCurvePoint.ControlTypeEnum.Absent) { return(BGCurveFormulas.BezierCubicDerivative(t, @from.PositionWorld, @from.ControlSecondWorld, to.ControlFirstWorld, to.PositionWorld).normalized); } return(BGCurveFormulas.BezierQuadraticDerivative(t, @from.PositionWorld, @from.ControlType == BGCurvePoint.ControlTypeEnum.Absent ? to.ControlFirstWorld : @from.ControlSecondWorld, to.PositionWorld).normalized); }
//copy paste from math, not sure how to refactor it public static Vector3 CalculatePosition(BGCurvePoint @from, BGCurvePoint to, float t) { if (@from.ControlType == BGCurvePoint.ControlTypeEnum.Absent && to.ControlType == BGCurvePoint.ControlTypeEnum.Absent) { return(Vector3.Lerp(@from.PositionWorld, to.PositionWorld, t)); } if (@from.ControlType != BGCurvePoint.ControlTypeEnum.Absent && to.ControlType != BGCurvePoint.ControlTypeEnum.Absent) { return(BGCurveFormulas.BezierCubic(t, @from.PositionWorld, @from.ControlSecondWorld, to.ControlFirstWorld, to.PositionWorld)); } return(BGCurveFormulas.BezierQuadratic(t, @from.PositionWorld, @from.ControlType == BGCurvePoint.ControlTypeEnum.Absent ? to.ControlFirstWorld : @from.ControlSecondWorld, to.PositionWorld)); }
public CurveData(TestCurves testCurves, string name, string description, Vector3 position, BGCurveBaseMath.Config config, MathTypeEnum mathType) : base(new GameObject(name), testCurves.LineRendererMaterial, Color.magenta) { this.testCurves = testCurves; this.description = description; //game object GameObject.transform.position = position; origin = position; //curve Curve = GameObject.AddComponent <BGCurve>(); Curve.Closed = testCurves.Curve.Closed; //add points for (var i = 0; i < testCurves.Curve.PointsCount; i++) { var point = testCurves.Curve[i]; var clonePoint = new BGCurvePoint(Curve, point.PositionLocal, point.ControlType, point.ControlFirstLocal, point.ControlSecondLocal); Curve.AddPoint(clonePoint); } //init math after points are added switch (mathType) { case MathTypeEnum.Base: Math = new BGCurveBaseMath(Curve, config); break; case MathTypeEnum.Formula: #pragma warning disable 0618 Math = new BGCurveFormulaMath(Curve, config); #pragma warning restore 0618 break; case MathTypeEnum.Adaptive: Math = new BGCurveAdaptiveMath(Curve, (BGCurveAdaptiveMath.ConfigAdaptive)config); break; default: throw new ArgumentOutOfRangeException("mathType", mathType, null); } AddObjects(ObjectsCount, testCurves.ObjectToMove, GameObject.transform); //scale down GameObject.transform.localScale = originalScale; }
//draw interactible selection icon control public void InspectorSelectionRect(BGCurvePoint point) { var currentEvent = Event.current; var rect = GUILayoutUtility.GetRect(24, 24, 24, 24, new GUIStyle { fixedWidth = 24, fixedHeight = 24, stretchWidth = false, stretchHeight = false }); if (currentEvent.isMouse) { if (currentEvent.type == EventType.mouseDown) { if (rect.Contains(currentEvent.mousePosition)) { groupSelectionStarted = true; groupSelectionIsSelecting = !Contains(point); GroupSelection(point); } } else if (groupSelectionStarted) { switch (currentEvent.type) { case EventType.MouseUp: groupSelectionStarted = false; break; case EventType.MouseDrag: if (rect.Contains(currentEvent.mousePosition)) { GroupSelection(point); } break; } } } var selected = Contains(point); var selectedTexture = selected ? tickYesTexture : tickNoTexture; var labelStyle = selected ? new GUIStyle("Label") { normal = new GUIStyleState { textColor = settings.LabelColorSelected } } : EditorStyles.label; EditorGUI.LabelField(rect, new GUIContent(selectedTexture, "Click to (de)select a point, or click and drag to (de)select multiple points. " + "Hold shift to use rectangular selection"), labelStyle); }
private void PointButtons(BGCurvePoint point, int index, BGCurveSettings settings) { if (!settings.ShowPointMenu) { return; } var curve = point.Curve; //================== Add before if (BGEditorUtility.ButtonWithIcon(addBeforeTexture, "Insert a point before this point")) { curve.AddPoint(BGNewPointPositionManager.InsertBefore(curve, index, settings.ControlType, settings.Sections), index); } GUILayout.Space(2); //=========================== Move Up if (index > 0 && BGEditorUtility.ButtonWithIcon(moveUpTexture, "Move the point up")) { curve.Swap(index - 1, index); } GUILayout.Space(2); //=========================== Move Down if (index < curve.PointsCount - 1 && BGEditorUtility.ButtonWithIcon(moveDownTexture, "Move the point down")) { curve.Swap(index, index + 1); } GUILayout.Space(2); //=========================== Delete if (BGEditorUtility.ButtonWithIcon(deleteTexture, "Delete the point")) { curve.Delete(index); editorSelection.Remove(point); GUIUtility.ExitGUI(); } }
public bool Contains(BGCurvePoint point) { return(points.Contains(point)); }
public bool SingleSelected(BGCurvePoint point) { return(points.Count == 1 && Contains(point)); }
public void OnSceneGUI(BGCurvePoint point, int index, BGCurveSettings settings, Quaternion rotation, Plane[] frustum) { var math = editor.Editor.Math; var positionWorld = math.GetPosition(index); if (settings.ShowControlHandles && settings.ShowCurve && (!editorSelection.HasSelected() || editorSelection.SingleSelected(point))) { // ============================================== Controls Handles if (point.ControlType != BGCurvePoint.ControlTypeEnum.Absent) { var controlFirstWorld = math.GetControlFirst(index); var controlSecondWorld = math.GetControlSecond(index); BGEditorUtility.SwapHandlesColor(settings.ControlHandlesColor, () => { Handles.DrawLine(positionWorld, controlFirstWorld); Handles.DrawLine(positionWorld, controlSecondWorld); // control handles different types var newPositionFirst = editor.Handle(GetUniqueNumber(index) - 1, settings.ControlHandlesType, controlFirstWorld, rotation, settings.ControlHandlesSettings); var newPositionSecond = editor.Handle(GetUniqueNumber(index) - 2, settings.ControlHandlesType, controlSecondWorld, rotation, settings.ControlHandlesSettings); if (BGEditorUtility.AnyChange(controlFirstWorld, newPositionFirst)) { point.ControlFirstWorld = newPositionFirst; } if (BGEditorUtility.AnyChange(controlSecondWorld, newPositionSecond)) { point.ControlSecondWorld = newPositionSecond; } }); if (settings.ShowControlLabels) { ShowControlLabel(settings, frustum, controlFirstWorld, point.ControlFirstLocal, "1"); ShowControlLabel(settings, frustum, controlSecondWorld, point.ControlSecondLocal, "2"); } } } //if only one point is selected and this is the selected point- do not print anything further if (editorSelection.HasSelected() && editorSelection.SingleSelected(point)) { return; } // ============================================== Labels & Positions if (settings.ShowLabels && GeometryUtility.TestPlanesAABB(frustum, new Bounds(positionWorld, Vector3.one))) { Handles.Label(editor.GetLabelPosition(settings, positionWorld), "Point " + index + (settings.ShowPositions ? " " + positionWorld : ""), editorSelection.Contains(point) ? selectedPositionLabelStyle : positionLabelStyle); } // ============================================== Move Handles if (!editorSelection.HasSelected() && settings.ShowCurve && settings.ShowHandles) { var newPos = editor.Handle(GetUniqueNumber(index), settings.HandlesType, positionWorld, rotation, settings.HandlesSettings); if (BGEditorUtility.AnyChange(positionWorld, newPos)) { point.PositionWorld = newPos; } } }
public static void AddPoint(BGCurve curve, BGCurvePoint point, int index) { BGPrivateField.Invoke(curve, BGCurve.MethodAddPoint, point, index, GetPointProvider(curve.PointsMode, curve)); }
public static BGCurvePoint CreatePoint(Vector3 position, BGCurve curve, BGCurvePoint.ControlTypeEnum controlType, int parts, out float distanceToPreviousPoint, out float distanceToNextPoint, bool ensureNew) { distanceToPreviousPoint = -1; distanceToNextPoint = -1; if (curve.PointsCount == 0) { //first point Vector3 control; switch (curve.Mode2D) { case BGCurve.Mode2DEnum.YZ: control = Vector3.forward; break; default: // BGCurve.Mode2DEnum.XY: // BGCurve.Mode2DEnum.Off: // BGCurve.Mode2DEnum.XZ: control = Vector3.right; break; } return(curve.CreatePointFromLocalPosition(curve.ToLocal(position), controlType, control, -control)); } parts = Mathf.Clamp(parts, 1, 50); //we no need no events (maybe check if point was actually added to a curve for events firing?) var oldSuppress = curve.SupressEvents; curve.SupressEvents = true; //create a point with no controls first BGCurvePoint newPoint; if (ensureNew) { newPoint = curve.CreatePointFromWorldPosition(position, BGCurvePoint.ControlTypeEnum.Absent); } else { if (point == null || point.Curve != curve) { point = curve.CreatePointFromWorldPosition(position, BGCurvePoint.ControlTypeEnum.Absent); } newPoint = point; newPoint.PositionWorld = position; newPoint.ControlFirstLocal = Vector3.zero; newPoint.ControlSecondLocal = Vector3.zero; } if (curve.Mode2DOn) { curve.Apply2D(newPoint); } //adjacent points var previousPoint = curve[curve.PointsCount - 1]; var nextPoint = curve.Closed ? curve[0] : null; //direction var tangent = BGEditorUtility.CalculateTangent(newPoint, previousPoint, nextPoint, 1 / (float)parts); if (tangent.sqrMagnitude < 0.0001f) { //whatever switch (curve.Mode2D) { case BGCurve.Mode2DEnum.Off: case BGCurve.Mode2DEnum.XY: case BGCurve.Mode2DEnum.XZ: tangent = Vector3.right; break; case BGCurve.Mode2DEnum.YZ: tangent = Vector3.up; break; } } //length distanceToPreviousPoint = BGEditorUtility.CalculateDistance(previousPoint, newPoint, parts); float minDistance; if (nextPoint != null) { distanceToNextPoint = BGEditorUtility.CalculateDistance(newPoint, nextPoint, parts); minDistance = Math.Min(distanceToPreviousPoint, distanceToNextPoint); } else { minDistance = distanceToPreviousPoint; } var length = minDistance * DistanceToControlMultiplier; //we need local tangent for controls tangent = curve.ToLocalDirection(tangent); newPoint.ControlSecondLocal = tangent * length; newPoint.ControlFirstLocal = -newPoint.ControlSecondLocal; newPoint.ControlType = controlType; curve.SupressEvents = oldSuppress; return(newPoint); }
internal void OnInspectorGUI(BGCurvePoint point, int index, BGCurveSettings settings) { var maskField = point.Curve.Mode2DOn && Event.current.type == EventType.Repaint; BGEditorUtility.HorizontalBox(() => { editorSelection.InspectorSelectionRect(point); BGEditorUtility.VerticalBox(() => { BGEditorUtility.SwapLabelWidth(60, () => { if (!settings.ShowPointPosition && !settings.ShowPointControlType) { BGEditorUtility.Horizontal(() => { EditorGUILayout.LabelField("Point " + index); PointButtons(point, index, settings); }); BGEditorUtility.StartIndent(1); } else { //control type if (settings.ShowPointControlType) { BGEditorUtility.Horizontal(() => { point.ControlType = (BGCurvePoint.ControlTypeEnum)EditorGUILayout.EnumPopup("Point " + index, point.ControlType); PointButtons(point, index, settings); }); BGEditorUtility.StartIndent(1); } //position if (settings.ShowPointPosition) { var math = editor.Editor.Math; var positionWorld = math.GetPosition(index); if (!settings.ShowPointControlType) { BGEditorUtility.Horizontal(() => { BGEditorUtility.Vector3Field("Point " + index, "Point's position in world space", positionWorld, vector3 => point.PositionWorld = vector3); if (maskField) { MaskFieldFor2D(point); } PointButtons(point, index, settings); }); BGEditorUtility.StartIndent(1); } else { BGEditorUtility.Vector3Field("Pos", "Point's position in world space", positionWorld, vector3 => point.PositionWorld = vector3); if (maskField) { MaskFieldFor2D(point); } } } } }); // control positions if (point.ControlType != BGCurvePoint.ControlTypeEnum.Absent && settings.ShowPointControlPositions) { // 1st BGEditorUtility.Vector3Field("Control 1", "Point 1st control position (local)", point.ControlFirstLocal, vector3 => { point.ControlFirstLocal = vector3; }); if (maskField) { MaskFieldFor2D(point); } // 2nd BGEditorUtility.Vector3Field("Control 2", "Point 2nd control position (local)", point.ControlSecondLocal, vector3 => { point.ControlSecondLocal = vector3; }); if (maskField) { MaskFieldFor2D(point); } } BGEditorUtility.EndIndent(1); }); }); }
protected static void DrawSection(BGCurvePoint from, BGCurvePoint to, int parts) { BGEditorUtility.Split(@from, to, parts, (fromPos, toPos) => Handles.DrawDottedLine(fromPos, toPos, 2)); }
protected virtual void AdditionalPreview(BGCurvePoint newPoint) { }