public void DrawInspector() { Spline spline = path.spline; if (spline == null) { return; } path.Transform(); EditorGUILayout.BeginVertical(); bool bezier = path.spline.type == Spline.Type.Bezier; bezier = EditorGUILayout.Toggle("Bezier", bezier); path.spline.type = bezier ? Spline.Type.Bezier : Spline.Type.Linear; path.seamlessEnds = EditorGUILayout.Toggle("Seamless Ends", path.seamlessEnds); path.spline.sampleRate = EditorGUILayout.IntField("Precision", path.spline.sampleRate); string[] options = new string[spline.points.Length + 1]; for (int i = 0; i < options.Length - 1; i++) { options[i + 1] = "Point " + (i + 1); } options[0] = "- None -"; EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); selectedPoint = EditorGUILayout.Popup("Select Point", selectedPoint + 1, options) - 1; if (selectedPoint > 0 && spline.points.Length > 2 && modifyWindow == null) { if (GUILayout.Button("X", GUILayout.Width(20))) { ArrayUtility.Remove(ref spline.points, spline.points[selectedPoint]); selectedPoint--; } } EditorGUILayout.EndHorizontal(); if (selectedPoint >= 0 && selectedPoint < spline.points.Length) { EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); if (tool == PathTool.Move) { GUI.backgroundColor = ForeverPrefs.highlightColor; } else { GUI.backgroundColor = Color.white; } if (GUILayout.Button("Move", EditorStyles.miniButtonLeft)) { tool = PathTool.Move; } if (tool == PathTool.Surface) { GUI.backgroundColor = ForeverPrefs.highlightColor; } else { GUI.backgroundColor = Color.white; } if (GUILayout.Button("Surface", EditorStyles.miniButtonMid)) { tool = PathTool.Surface; } if (tool == PathTool.Normal) { GUI.backgroundColor = ForeverPrefs.highlightColor; } else { GUI.backgroundColor = Color.white; } if (GUILayout.Button("Normals", EditorStyles.miniButtonRight)) { tool = PathTool.Normal; } EditorGUILayout.EndHorizontal(); GUI.backgroundColor = Color.white; if (tool == PathTool.Surface) { surfaceLayermask = DreamteckEditorGUI.LayermaskField("Layer Mask", surfaceLayermask); } EditorGUILayout.Space(); SplinePoint avgPoint = spline.points[selectedPoint]; avgPoint.SetPosition(EditorGUILayout.Vector3Field("Position", avgPoint.position)); if (spline.type == Spline.Type.Bezier) { EditorGUILayout.Space(); avgPoint.type = (SplinePoint.Type)EditorGUILayout.EnumPopup("Tangents Type", avgPoint.type); avgPoint.SetTangent2Position(EditorGUILayout.Vector3Field("Front Tangent", avgPoint.tangent2)); avgPoint.SetTangentPosition(EditorGUILayout.Vector3Field("Back Tangent", avgPoint.tangent)); EditorGUILayout.Space(); } else { avgPoint.tangent = avgPoint.position; avgPoint.tangent2 = avgPoint.position; } avgPoint.normal = EditorGUILayout.Vector3Field("Normal", avgPoint.normal); avgPoint.normal.Normalize(); EditorGUIUtility.labelWidth = 0f; avgPoint.size = EditorGUILayout.FloatField("Size", avgPoint.size); avgPoint.color = EditorGUILayout.ColorField("Color", avgPoint.color); Undo.RecordObject(segment, "Edit Path " + path.name); spline.points[selectedPoint] = avgPoint; if (GUI.changed) { path.InverseTransform(); } } if (modifyWindow == null) { EditorGUILayout.Space(); EditorGUILayout.LabelField("Insert Point", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("At Start")) { SplineSample result = spline.Evaluate(DMath.Lerp(0.0, 1.0 / (spline.points.Length - 1), 0.5)); float tangentLength = Mathf.Lerp(Vector3.Distance(spline.points[0].position, spline.points[0].tangent), Vector3.Distance(spline.points[1].position, spline.points[1].tangent), 0.5f); ArrayUtility.Insert(ref spline.points, 1, new SplinePoint(result.position, result.position - result.forward * tangentLength, result.up, result.size, result.color)); path.InverseTransform(); selectedPoint = 1; } if (GUILayout.Button("At End")) { SplineSample result = spline.Evaluate(DMath.Lerp((double)(spline.points.Length - 2) / (spline.points.Length - 1), 1.0, 0.5)); float tangentLength = Mathf.Lerp(Vector3.Distance(spline.points[spline.points.Length - 2].position, spline.points[spline.points.Length - 2].tangent), Vector3.Distance(spline.points[spline.points.Length - 1].position, spline.points[spline.points.Length - 1].tangent), 0.5f); ArrayUtility.Insert(ref spline.points, spline.points.Length - 2, new SplinePoint(result.position, result.position - result.forward * tangentLength, result.up, result.size, result.color)); path.InverseTransform(); selectedPoint = spline.points.Length - 2; } EditorGUILayout.EndHorizontal(); if (GUILayout.Button("Modify Path")) { modifyWindow = EditorWindow.GetWindow <ModifyWindow>(true); modifyWindow.Init(this); } } EditorGUILayout.EndVertical(); }
protected virtual void OnSceneGUI() { Node node = (Node)target; Node.Connection[] connections = node.GetConnections(); for (int i = 0; i < connections.Length; i++) { DSSplineDrawer.DrawSplineComputer(connections[i].spline, 0.0, 1.0, 0.5f); } bool update = false; if (position != node.transform.position) { position = node.transform.position; update = true; } if (scale != node.transform.localScale) { scale = node.transform.localScale; update = true; } if (rotation != node.transform.rotation) { rotation = node.transform.rotation; update = true; } if (update) { node.UpdateConnectedComputers(); } if (addComp == null) { if (connections.Length > 0) { bool bezier = false; for (int i = 0; i < connections.Length; i++) { if (connections[i].spline == null) { continue; } if (connections[i].spline.type == Spline.Type.Bezier) { bezier = true; continue; } } if (bezier && node.type == Node.Type.Smooth) { if (connections[0].spline != null) { SplinePoint point = node.GetPoint(0, true); Handles.DrawDottedLine(node.transform.position, point.tangent, 6f); Handles.DrawDottedLine(node.transform.position, point.tangent2, 6f); Vector3 lastPos = point.tangent; bool setPoint = false; point.SetTangentPosition(Handles.PositionHandle(point.tangent, node.transform.rotation)); if (lastPos != point.tangent) { setPoint = true; } lastPos = point.tangent2; point.SetTangent2Position(Handles.PositionHandle(point.tangent2, node.transform.rotation)); if (lastPos != point.tangent2) { setPoint = true; } if (setPoint) { node.SetPoint(0, point, true); node.UpdateConnectedComputers(); } } } } return; } SplinePoint[] points = addComp.GetPoints(); Transform camTransform = SceneView.currentDrawingSceneView.camera.transform; DSSplineDrawer.DrawSplineComputer(addComp, 0.0, 1.0, 0.5f); TextAnchor originalAlignment = GUI.skin.label.alignment; Color originalColor = GUI.skin.label.normal.textColor; GUI.skin.label.alignment = TextAnchor.MiddleCenter; GUI.skin.label.normal.textColor = addComp.editorPathColor; for (int i = 0; i < availablePoints.Length; i++) { if (addComp.isClosed && i == points.Length - 1) { break; } Handles.Label(points[i].position + Camera.current.transform.up * HandleUtility.GetHandleSize(points[i].position) * 0.3f, (i + 1).ToString()); if (SplineEditorHandles.CircleButton(points[availablePoints[i]].position, Quaternion.LookRotation(-camTransform.forward, camTransform.up), HandleUtility.GetHandleSize(points[availablePoints[i]].position) * 0.1f, 2f, addComp.editorPathColor)) { AddConnection(addComp, availablePoints[i]); break; } } GUI.skin.label.alignment = originalAlignment; GUI.skin.label.normal.textColor = originalColor; }
public void PlaceObjects() { // recreate and redistribute all prefabs if requested if (!prefabPainter.splineSettings.reusePrefabs) { RemoveAllPrefabInstances(); } if (prefabPainter.splineSettings.controlPoints.Count < 2) { // remove all that's left in case control points were deleted RemoveAllPrefabInstances(); // don't continue any further return; } // put the spline into a list of Vector3's instead of using the iterator IEnumerable <Vector3> spline = CreateSpline(); IEnumerator iterator = spline.GetEnumerator(); List <SplinePoint> splinePoints = new List <SplinePoint>(); // limit the number of points; this has become necessary because with the loop there's an overlap multiple times // and this could result in an endless loop in the worst case int splinePointMaxIndex = (prefabPainter.splineSettings.curveResolution + 1) * prefabPainter.splineSettings.controlPoints.Count; int splinePointIndex = 0; int segmentIndex = 0; int controlPointIndex = 0; while (iterator.MoveNext() && splinePointIndex <= splinePointMaxIndex) { SplinePoint splinePoint = new SplinePoint(); splinePoint.position = (Vector3)iterator.Current; splinePoint.startControlPointIndex = controlPointIndex; splinePoints.Add(splinePoint); splinePointIndex++; segmentIndex++; if (segmentIndex > prefabPainter.splineSettings.curveResolution) { controlPointIndex++; segmentIndex = 0; } } //distanceToMove represents how much farther we need to progress down the spline before we place the next object int nextSplinePointIndex = 1; //our current position on the spline Vector3 positionIterator = splinePoints[0].position; // the algorithm skips the first control point, so we need to manually place the first object Vector3 direction = (splinePoints[nextSplinePointIndex].position - positionIterator); int prefabInstanceIndex = -1; // new prefab GameObject prefab = AddPrefab(ref prefabInstanceIndex, positionIterator, direction, splinePoints, nextSplinePointIndex - 1); float distanceToMove = GetDistanceToMove(prefab); while (nextSplinePointIndex < splinePoints.Count) { direction = (splinePoints[nextSplinePointIndex].position - positionIterator); direction = direction.normalized; float distanceToNextPoint = Vector3.Distance(positionIterator, splinePoints[nextSplinePointIndex].position); if (distanceToNextPoint >= distanceToMove) { positionIterator += direction * distanceToMove; // new prefab prefab = AddPrefab(ref prefabInstanceIndex, positionIterator, direction, splinePoints, nextSplinePointIndex - 1); distanceToMove = GetDistanceToMove(prefab); } else { distanceToMove -= distanceToNextPoint; positionIterator = splinePoints[nextSplinePointIndex++].position; } } // remove prefab instances that aren't used anymore if (prefabPainter.splineSettings.reusePrefabs) { RemovePrefabInstances(prefabInstanceIndex); } }
public float2 GetControlPoint(int i, SplinePoint point) => GetControlPoint2DLocal(i);
public void RefreshTreeView(SplinePoint splinePoint) { GuiData.SplineListDisplay.UpdateToList(splinePoint); }
public void DoMirror() { List <int> half = GetHalf(ref originalPoints); int welded = -1; if (half.Count > 0) { if (flip) { if (IsWeldable(originalPoints[half[0]])) { welded = half[0]; half.RemoveAt(0); } } else { if (IsWeldable(originalPoints[half[half.Count - 1]])) { welded = half[half.Count - 1]; half.RemoveAt(half.Count - 1); } } int offset = welded >= 0 ? 1 : 0; int additionalSlot = isClosed && half.Count > 0 ? 1 : 0; if (additionalSlot > 0) { if (flip) { if (IsWeldable(originalPoints[half[half.Count - 1]])) { additionalSlot = 0; } } else { if (IsWeldable(originalPoints[half[0]])) { additionalSlot = 0; } } } int mirroredLength = half.Count * 2 + offset + additionalSlot; if (mirrored.Length != mirroredLength) { mirrored = new SplinePoint[mirroredLength]; } for (int i = 0; i < half.Count; i++) { if (flip) { mirrored[i] = new SplinePoint(originalPoints[half[(half.Count - 1) - i]]); mirrored[i + half.Count + offset] = GetMirrored(originalPoints[half[i]]); SwapTangents(ref mirrored[i]); SwapTangents(ref mirrored[i + half.Count + offset]); } else { mirrored[i] = new SplinePoint(originalPoints[half[i]]); mirrored[i + half.Count + offset] = GetMirrored(originalPoints[half[(half.Count - 1) - i]]); } } if (welded >= 0) { mirrored[half.Count] = new SplinePoint(originalPoints[welded]); if (flip) { SwapTangents(ref mirrored[half.Count]); } MakeMiddlePoint(ref mirrored[half.Count]); } if (isClosed && mirrored.Length > 0) { if (additionalSlot == 0) { MakeMiddlePoint(ref mirrored[0]); } mirrored[mirrored.Length - 1] = new SplinePoint(mirrored[0]); } } else { mirrored = new SplinePoint[0]; } points = mirrored; SetDirty(); }
public void AddSplinePoint(SplinePoint p) { points.Add(p); }
public float3 GetControlPoint(ISimpleSpline3D spline, int index, SplinePoint pointType) { Assert.NotNull(spline); return(spline.GetControlPoint(index, pointType)); }
private void PathArcTo(string coords, bool relative) { // Get Arc Arguments float[] floats = ParseFloat(coords); float rx = floats[0]; float ry = floats[1]; float rotation = floats[2] * Mathf.Deg2Rad; bool largeArc = floats[3] > 0.5f; bool sweep = floats[4] > 0.5f; float x = floats[5]; float y = floats[6]; // Set the last buffer point to broken SplinePoint p = buffer.GetLastPoint(); p.type = SplinePoint.Type.Broken; // Get the start and end point. Note: Flip Y, as the Ellipse Parameters calculation assumes positive Y values Vector3 sp = p.position; sp.y *= -1; Vector3 ep = new Vector3(x, y, 0); if (relative) { ep += sp; } Vector2 c; float theta1; float sweepTheta; float adjustedRx; float adjustedRy; // Get the Ellipse Parameters CalculateEllipseParams(sp, ep, rotation, rx, ry, largeArc, sweep, out c, out theta1, out sweepTheta, out adjustedRx, out adjustedRy); // Flip the center Y back c.y *= -1; // Generate the ellipse primitive. Note: Rotated by -90 degrees and flipped, so first point starts at +X and goes clockwise Ellipse ellipse = new Ellipse(); ellipse.offset = c; ellipse.rotation = new Vector3(0, 0, -90 - rotation * Mathf.Rad2Deg); ellipse.xRadius = adjustedRx; ellipse.yRadius = adjustedRy; var ellipseSpline = ellipse.CreateSpline(); var esp = ellipseSpline.points; var tmpp = esp[1]; esp[1] = esp[3]; esp[3] = tmpp; for (int i = 0; i < esp.Length; i++) { FlipTangents(ref esp[i]); } // Find the percentages to sample the ellipse at var startP = theta1 / (Mathf.PI * 2); startP = ModP(startP, 1f); var sweepP = sweepTheta / (Mathf.PI * 2); var endP = startP + sweepP; var percentages = GetArcSegmentPercentages(startP, endP); // Sample the ellipse and add points to buffer for (int i = 1; i < percentages.Length; ++i) { double pp = percentages[i - 1]; double pc = percentages[i]; double pr = pc - pp; int sgn = Math.Sign(pr); // This sign indicates a reversed range if < 0; The sampled tangents need to be flipped if this is the case pr *= sgn; if (pr < 0.0001d) { continue; // Sample error margin } double d = 0.75d / pr; pc = ModP(pc, 1d); pp = ModP(pp, 1d); // New point in buffer Vector3 posc = Vector3.zero, tanc = Vector3.zero, tanp = Vector3.zero; ellipseSpline.EvaluatePosition(ref posc, pc); ellipseSpline.EvaluateTangent(ref tanc, pc); tanc *= sgn; tanc /= (float)d; buffer.position = posc; buffer.tangent = posc - tanc; // Modify tangent2 of last point in buffer ellipseSpline.EvaluateTangent(ref tanp, pp); tanp *= sgn; tanp /= (float)d; p = buffer.GetLastPoint(); p.type = SplinePoint.Type.Broken; p.SetTangent2Position(p.position + tanp); buffer.SetLastPoint(p); buffer.CreateBroken(); } }
internal void CreateClosingPoint() { SplinePoint p = new SplinePoint(points[0]); points.Add(p); }
internal void UpdateToList(SplinePoint splinePoint) { this.SplineListDisplayControl.UpdateListDisplay(splinePoint); }
private void UpdateVisualizer() { if (visualizer == null) { visualizer = new Spline(splineType); } visualizer.type = splineType; visualizer.sampleRate = sampleRate; if (placementMode == PlacementMode.Insert) { visualizer.points = points; if (isClosed) { visualizer.Close(); } else if (visualizer.isClosed) { visualizer.Break(); } return; } if (visualizer.points.Length != points.Length + 1) { visualizer.points = new SplinePoint[points.Length + 1]; } SplinePoint newPoint = new SplinePoint(createPoint, createPoint, createNormal, 1f, Color.white); if (appendMode == AppendMode.End) { if (isClosed) { for (int i = 0; i < points.Length; i++) { visualizer.points[i] = points[i]; } visualizer.points[visualizer.points.Length - 2] = newPoint; visualizer.points[visualizer.points.Length - 1] = points[points.Length - 1]; } else { for (int i = 0; i < points.Length; i++) { visualizer.points[i] = points[i]; } visualizer.points[visualizer.points.Length - 1] = newPoint; } } else { if (isClosed) { for (int i = 1; i < points.Length; i++) { visualizer.points[i] = points[i - 1]; } visualizer.points[1] = newPoint; visualizer.points[0] = points[0]; } else { for (int i = 1; i < visualizer.points.Length; i++) { visualizer.points[i] = points[i - 1]; } visualizer.points[0] = newPoint; } } if (isClosed && !visualizer.isClosed) { visualizer.Close(); } else if (visualizer.isClosed) { visualizer.Break(); } if (visualizer.isClosed) { visualizer.points[0].SetPosition(createPoint); } }
public void HighlightNoCall(SplinePoint splinePoint) { mListDisplayWindow.HighlightObjectNoCall(splinePoint, false); }
private void MouseGrabbingActivity() { Cursor cursor = GuiManager.Cursor; if (cursor.PrimaryPush && GuiManager.Cursor.WindowOver == null) { mCurrentSplinePoint = null; if (mReactiveHud.SplineMover.IsMouseOver == false) { mSwitchedCurrentOnLastPush = mCurrentSpline != mSplineOver; CurrentSpline = mSplineOver; // Make sure we set the CurrentSplinePoint after setting the CurrentSpline so that // the GUI for the CurrentSpline is already set. CurrentSplinePoint = mSplinePointOver; mGrabbedSplinePoint = mSplinePointOver; if (mGrabbedSplinePoint != null) { float cursorX = cursor.WorldXAt(mGrabbedSplinePoint.Position.Z); float cursorY = cursor.WorldYAt(mGrabbedSplinePoint.Position.Z); mXGrabOffset = mGrabbedSplinePoint.Position.X - cursorX; mYGrabOffset = mGrabbedSplinePoint.Position.Y - cursorY; } } // else if over the spline mover, let the current spline point stay at null } if (cursor.PrimaryDown && mGrabbedSplinePoint != null) { if (mHandleIndexOver0Base != -1) { float cursorX = cursor.WorldXAt(mGrabbedSplinePoint.Position.Z); float cursorY = cursor.WorldYAt(mGrabbedSplinePoint.Position.Z); float differenceX = cursorX - mGrabbedSplinePoint.Position.X; float differenceY = cursorY - mGrabbedSplinePoint.Position.Y; differenceX *= 2; differenceY *= 2; if (mHandleIndexOver0Base == 0) { // Index 0 goes negative, index 1 goes positive differenceX *= -1; differenceY *= -1; } mGrabbedSplinePoint.Velocity.X = differenceX; mGrabbedSplinePoint.Velocity.Y = differenceY; } else if (!mSwitchedCurrentOnLastPush) { mGrabbedSplinePoint.Position = new Vector3( cursor.WorldXAt(mGrabbedSplinePoint.Position.Z) + mXGrabOffset, cursor.WorldYAt(mGrabbedSplinePoint.Position.Z) + mYGrabOffset, mGrabbedSplinePoint.Position.Z); } } if (cursor.PrimaryClick) { mGrabbedSplinePoint = null; GuiData.PropertyGrid.Refresh(); } }
protected void BuildSegment(SplineSegment ss, SplinePoint p1, SplinePoint p2, SplinePoint p3, SplinePoint p4) { if (InterpolateType == SplineType.Linear) { PreparePoint(p1, p2, p3); PreparePoint(p2, p3, p4); ss.mStartpos = p2.mPoint; ss.mEndpos = p3.mPoint; ss.mStartctrl = ss.mStartpos + p2.mNextctrl; ss.mEndctrl = ss.mEndpos + p3.mPrevctrl; } if (InterpolateType == SplineType.Bezier) { PreparePoint(p1, p2, p3); PreparePoint(p2, p3, p4); ss.mStartpos = p2.mPoint; ss.mEndpos = p3.mPoint; ss.mStartctrl = ss.mStartpos + p2.mNextctrl; ss.mEndctrl = ss.mEndpos + p3.mPrevctrl; } else if (InterpolateType == SplineType.CatmullRom) { ss.mStartpos = p1.mPoint; ss.mEndpos = p4.mPoint; ss.mStartctrl = p2.mPoint; ss.mEndctrl = p3.mPoint; } ss.mStartlen = Length; float seglen = GetLength(ss); Length += seglen; ss.mLength = seglen; ss.mEndlen = Length; switch (Reparam) { case ReparamType.None: ss.mParams = null; ss.mPrecomps = null; break; case ReparamType.Simple: { mPrecompdiv = 1 / (float)StepCount; float param = 0, length = 0; Vector3 prev, next; ss.mParams = new float[StepCount + 1]; ss.mPrecomps = new float[StepCount + 1]; for (int i = 1; i < StepCount + 1; ++i) { prev = GetPosition(ss, param); param += mPrecompdiv; next = GetPosition(ss, param); length += (next - prev).magnitude; ss.mPrecomps[i] = length / seglen; ss.mParams[i] = param; } ss.mParams[0] = 0; ss.mParams[StepCount] = 1; ss.mPrecomps[0] = 0; ss.mPrecomps[StepCount] = 1; mPrecompdiv = 1 / (float)StepCount; } break; case ReparamType.RungeKutta: float dlen = seglen / (float)StepCount, lparam = 0; ss.mParams = new float[StepCount + 1]; ss.mPrecomps = new float[StepCount + 1]; for (int i = 0; i < StepCount + 1; ++i) { ss.mParams[i] = GetReparamRungeKutta(ss, lparam); ss.mPrecomps[i] = lparam / seglen; lparam += dlen; } ss.mParams[0] = 0; ss.mParams[StepCount] = 1; ss.mPrecomps[0] = 0; ss.mPrecomps[StepCount] = 1; mPrecompdiv = 1 / (float)StepCount; break; } }
void PointMenu() { if (selectedPoints.Count == 0 || points.Length == 0) { return; } //Otherwise show the editing menu + the point selection menu Vector3 avgPos = Vector3.zero; Vector3 avgTan = Vector3.zero; Vector3 avgTan2 = Vector3.zero; Vector3 avgNormal = Vector3.zero; float avgSize = 0f; Color avgColor = Color.clear; for (int i = 0; i < selectedPoints.Count; i++) { avgPos += points[selectedPoints[i]].position; avgNormal += points[selectedPoints[i]].normal; avgSize += points[selectedPoints[i]].size; avgTan += points[selectedPoints[i]].tangent; avgTan2 += points[selectedPoints[i]].tangent2; avgColor += points[selectedPoints[i]].color; } avgPos /= selectedPoints.Count; avgTan /= selectedPoints.Count; avgTan2 /= selectedPoints.Count; avgSize /= selectedPoints.Count; avgColor /= selectedPoints.Count; avgNormal.Normalize(); SplinePoint avgPoint = new SplinePoint(avgPos, avgPos); avgPoint.tangent = avgTan; avgPoint.tangent2 = avgTan2; avgPoint.size = avgSize; avgPoint.color = avgColor; avgPoint.type = points[selectedPoints[0]].type; SplinePoint.Type lastType = avgPoint.type; avgPoint.normal = avgNormal; EditorGUI.BeginChangeCheck(); SplineComputer.Space lastSpace = SplinePrefs.pointEditSpace; SplinePrefs.pointEditSpace = (SplineComputer.Space)EditorGUILayout.EnumPopup("Edit Space", SplinePrefs.pointEditSpace); if (lastSpace != SplinePrefs.pointEditSpace) { SplinePrefs.SavePrefs(); } if (splineType == Spline.Type.Bezier) { if (is2D) { avgPoint.SetTangentPosition(TransformedPositionField2D("Tangent 1", avgPoint.tangent)); avgPoint.SetTangent2Position(TransformedPositionField2D("Tangent 2", avgPoint.tangent2)); } else { avgPoint.SetTangentPosition(TransformedPositionField("Tangent 1", avgPoint.tangent)); avgPoint.SetTangent2Position(TransformedPositionField("Tangent 2", avgPoint.tangent2)); } } if (is2D) { avgPoint.SetPosition(TransformedPositionField2D("Position", avgPoint.position)); } else { avgPoint.SetPosition(TransformedPositionField("Position", avgPoint.position)); } if (!is2D) { if (SplinePrefs.pointEditSpace == SplineComputer.Space.Local) { avgPoint.normal = _matrix.inverse.MultiplyVector(avgPoint.normal); } avgPoint.normal = TransformedPositionField("Normal", avgPoint.normal); if (SplinePrefs.pointEditSpace == SplineComputer.Space.Local) { avgPoint.normal = _matrix.MultiplyVector(avgPoint.normal); } } avgPoint.size = EditorGUILayout.FloatField("Size", avgPoint.size); avgPoint.color = EditorGUILayout.ColorField("Color", avgPoint.color); if (splineType == Spline.Type.Bezier) { avgPoint.type = (SplinePoint.Type)EditorGUILayout.EnumPopup("Point Type", avgPoint.type); } if (!EditorGUI.EndChangeCheck()) { return; } RecordUndo("Edit Points"); for (int i = 0; i < selectedPoints.Count; i++) { points[selectedPoints[i]].SetPosition(GetChangedVector(avgPos, avgPoint.position, points[selectedPoints[i]].position)); points[selectedPoints[i]].normal = GetChangedVector(avgNormal, avgPoint.normal, points[selectedPoints[i]].normal); if (splineType == Spline.Type.Bezier) { points[selectedPoints[i]].SetTangentPosition(GetChangedVector(avgTan, avgPoint.tangent, points[selectedPoints[i]].tangent)); points[selectedPoints[i]].SetTangent2Position(GetChangedVector(avgTan2, avgPoint.tangent2, points[selectedPoints[i]].tangent2)); } if (avgPoint.size != avgSize) { points[selectedPoints[i]].size = avgPoint.size; } if (avgColor != avgPoint.color) { points[selectedPoints[i]].color = avgPoint.color; } if (lastType != avgPoint.type) { points[selectedPoints[i]].type = avgPoint.type; } } }
public void UpdateControlPointLocal(int index, float2 point, SplinePoint mode) { UpdateControlPointLocal(index, point, TranslateVariancePoint(mode)); }
public void UpdateControlPoint(ISimpleSpline3D spline, int index, float3 newPoint, SplinePoint pointType) { ISpline3DEditor spline3D = spline as ISpline3DEditor; Assert.NotNull(spline3D); spline3D.UpdateControlPointWorld(index, newPoint, pointType); }
public float2 GetControlPoint(int i, SplinePoint point) { return(GetControlPoint(i, TranslateVariancePoint(point))); }
private void AddGrindTriggers(GameObject go) { foreach (Transform transform in go.GetComponentsInChildren <Transform>()) { if (transform.name.Contains("GrindSpline")) { Transform grindColliders = new GameObject(transform.name + "Colliders").transform; grindColliders.parent = go.transform; grindColliders.gameObject.layer = 12; if (transform.name.Contains("Metal")) { transform.tag = "Metal"; } if (transform.name.Contains("Wood")) { transform.tag = "Wood"; } if (transform.name.Contains("Concrete")) { transform.tag = "Concrete"; } Vector3[] grindPoints = new Vector3[transform.childCount]; SplinePoint[] splinePoints = new SplinePoint[grindPoints.Length]; for (int i = 0; i < grindPoints.Length; i++) { grindPoints[i] = transform.GetChild(i).position; splinePoints[i] = new SplinePoint(grindPoints[i]); } SplineComputer splineComputer = grindColliders.gameObject.AddComponent <SplineComputer>(); splineComputer.type = Spline.Type.Linear; Vector3[] grindNormals = new Vector3[grindPoints.Length]; for (int i = 0; i < grindPoints.Length - 1; i++) { GameObject grindCollider = new GameObject("RailCol" + i); grindCollider.layer = 12; grindCollider.transform.position = grindPoints[i]; grindCollider.transform.LookAt(grindPoints[i + 1]); BoxCollider boxCollider = grindCollider.AddComponent <BoxCollider>(); float segmentLength = Vector3.Distance(grindPoints[i], grindPoints[i + 1]); boxCollider.size = new Vector3(0.08f / go.transform.lossyScale.x, 0.08f / go.transform.lossyScale.y, segmentLength); boxCollider.center = Vector3.forward * segmentLength / 2f; boxCollider.isTrigger = true; grindCollider.transform.parent = grindColliders; grindNormals[i] = grindCollider.transform.up; if (transform.name.Contains("Metal")) { grindCollider.tag = "Metal"; } if (transform.name.Contains("Wood")) { grindCollider.tag = "Wood"; } if (transform.name.Contains("Concrete")) { grindCollider.tag = "Concrete"; } } grindNormals[grindNormals.Length - 1] = grindNormals[grindNormals.Length - 2]; splineComputer.SetPoints(splinePoints); splineComputer.Evaluate(0.9); for (int i = 0; i < grindPoints.Length; i++) { splineComputer.SetPointNormal(i, splineComputer.GetPointNormal(i, SplineComputer.Space.World) + grindNormals[i], SplineComputer.Space.World); } } if (transform.name.Contains("GrindCollider")) { transform.localScale = new Vector3(1f / go.transform.lossyScale.x, 1f / go.transform.lossyScale.y, transform.localScale.z); } } }
private SplinePointVariance TranslateVariancePoint(SplinePoint point) { return((SplinePointVariance)point); }
void Merge(int index, MergeSide mergingSide) { RecordUndo("Merge Splines"); SplineComputer mergedSpline = availableMergeComputers[index]; SplinePoint[] mergedPoints = mergedSpline.GetPoints(); SplinePoint[] original = spline.GetPoints(); List <SplinePoint> pointsList = new List <SplinePoint>(); SplinePoint[] points; if (!mergeEndpoints) { points = new SplinePoint[mergedPoints.Length + original.Length]; } else { points = new SplinePoint[mergedPoints.Length + original.Length - 1]; } if (mergeSide == MergeSide.End) { if (mergingSide == MergeSide.Start) { for (int i = 0; i < original.Length; i++) { pointsList.Add(original[i]); } for (int i = mergeEndpoints ? 1 : 0; i < mergedPoints.Length; i++) { pointsList.Add(mergedPoints[i]); } } else { for (int i = 0; i < original.Length; i++) { pointsList.Add(original[i]); } for (int i = 0; i < mergedPoints.Length - (mergeEndpoints ? 1 : 0); i++) { pointsList.Add(mergedPoints[(mergedPoints.Length - 1) - i]); } } } else { if (mergingSide == MergeSide.Start) { for (int i = 0; i < mergedPoints.Length - (mergeEndpoints ? 1 : 0); i++) { pointsList.Add(mergedPoints[(mergedPoints.Length - 1) - i]); } for (int i = 0; i < original.Length; i++) { pointsList.Add(original[i]); } } else { for (int i = mergeEndpoints ? 1 : 0; i < mergedPoints.Length; i++) { pointsList.Add(mergedPoints[i]); } for (int i = 0; i < original.Length; i++) { pointsList.Add(original[i]); } } } points = pointsList.ToArray(); double mergedPercent = (double)(mergedPoints.Length - 1) / (points.Length - 1); double from = 0.0; double to = 1.0; if (mergeSide == MergeSide.End) { from = 1.0 - mergedPercent; to = 1.0; } else { from = 0.0; to = mergedPercent; } List <Node> mergedNodes = new List <Node>(); List <int> mergedIndices = new List <int>(); for (int i = 0; i < mergedSpline.pointCount; i++) { Node node = mergedSpline.GetNode(i); if (node != null) { mergedNodes.Add(node); mergedIndices.Add(i); Undo.RecordObject(node, "Disconnect Node"); mergedSpline.DisconnectNode(i); i--; } } SplineUser[] subs = mergedSpline.GetSubscribers(); for (int i = 0; i < subs.Length; i++) { mergedSpline.Unsubscribe(subs[i]); subs[i].spline = spline; subs[i].clipFrom = DMath.Lerp(from, to, subs[i].clipFrom); subs[i].clipTo = DMath.Lerp(from, to, subs[i].clipTo); } spline.SetPoints(points); if (mergeSide == MergeSide.Start) { spline.ShiftNodes(0, spline.pointCount - 1, mergedSpline.pointCount); for (int i = 0; i < mergedNodes.Count; i++) { spline.ConnectNode(mergedNodes[i], mergedIndices[i]); } } else { for (int i = 0; i < mergedNodes.Count; i++) { int connectIndex = mergedIndices[i] + original.Length; if (mergeEndpoints) { connectIndex--; } spline.ConnectNode(mergedNodes[i], connectIndex); } } if (EditorUtility.DisplayDialog("Keep merged computer's GameObject?", "Do you want to keep the merged computer's game object?", "Yes", "No")) { Undo.DestroyObjectImmediate(mergedSpline); } else { for (int i = 0; i < mergedNodes.Count; i++) { if (TransformUtility.IsParent(mergedNodes[i].transform, mergedSpline.transform)) { Undo.SetTransformParent(mergedNodes[i].transform, mergedSpline.transform.parent, "Reparent Node"); } } Undo.DestroyObjectImmediate(mergedSpline.gameObject); } FindAvailableComputers(); }
/// <summary> /// Get the control point at <paramref name="index"/> from <paramref name="spline"/> /// </summary> public abstract float3 GetControlPoint(T spline, int index, SplinePoint pointType);
public virtual void DuplicateSelected() { if (selectedPoints.Count == 0) { return; } RecordUndo("Duplicate Points"); SplinePoint[] newPoints = new SplinePoint[points.Length + selectedPoints.Count]; SplinePoint[] duplicated = new SplinePoint[selectedPoints.Count]; int index = 0; for (int i = 0; i < selectedPoints.Count; i++) { duplicated[index++] = points[selectedPoints[i]]; } int min = points.Length - 1, max = 0; for (int i = 0; i < selectedPoints.Count; i++) { if (selectedPoints[i] < min) { min = selectedPoints[i]; } if (selectedPoints[i] > max) { max = selectedPoints[i]; } } int[] selected = selectedPoints.ToArray(); selectedPoints.Clear(); if (duplicationDirection == Spline.Direction.Backward) { for (int i = 0; i < min; i++) { newPoints[i] = points[i]; } for (int i = 0; i < duplicated.Length; i++) { newPoints[i + min] = duplicated[i]; selectedPoints.Add(i + min); } for (int i = min; i < points.Length; i++) { newPoints[i + duplicated.Length] = points[i]; } } else { for (int i = 0; i <= max; i++) { newPoints[i] = points[i]; } for (int i = 0; i < duplicated.Length; i++) { newPoints[i + max + 1] = duplicated[i]; selectedPoints.Add(i + max + 1); } for (int i = max + 1; i < points.Length; i++) { newPoints[i + duplicated.Length] = points[i]; } } points = newPoints; if (onDuplicatePoint != null) { onDuplicatePoint(selected); } }
/// <summary> /// Abstraction of updating an existing point so that 2D and 3D can share the same tests /// </summary> public abstract void UpdateControlPoint(T spline, int index, float3 newPoint, SplinePoint pointType);
public static void ConvertBezdatToTubes(string bezdatFilePath, string tubesFilePath, bool generatePlainTextVersion = false) { System.IO.StreamReader file = null; try { file = new System.IO.StreamReader(bezdatFilePath); } catch (Exception e) { Console.WriteLine("ERROR: Could not open file '" + bezdatFilePath.ToString() + "'."); Console.WriteLine(e.Message); return; } var firstLine = file.ReadLine(); if (firstLine == null && firstLine != "BezDatA 1.0") { Console.WriteLine("ERROR: Expected to read 'BezDatA 1.0' on first line, but read '" + firstLine + "' instead."); return; } var points = new System.Collections.Generic.List<Point>(); var indices = new System.Collections.Generic.List<int>(); var maxIndex = 0; var lineCounter = 1; string line; while ((line = file.ReadLine()) != null) { string[] strs = line.Split(null); var len = strs.Length; if (len > 0) { if (strs[0] == "PT") { if (len != 8) { Console.WriteLine("ERROR: Expected 7 values on line " + lineCounter.ToString() + ", but read " + (len - 1).ToString() + " values instead."); file.Close(); return; } try { var point = new Point(); point.Px = Convert.ToSingle(strs[1], System.Globalization.CultureInfo.InvariantCulture); point.Py = Convert.ToSingle(strs[2], System.Globalization.CultureInfo.InvariantCulture); point.Pz = Convert.ToSingle(strs[3], System.Globalization.CultureInfo.InvariantCulture); point.R = Convert.ToSingle(strs[4], System.Globalization.CultureInfo.InvariantCulture); point.Cr = (float)Math.Pow(Convert.ToDouble(strs[5], System.Globalization.CultureInfo.InvariantCulture) / 255.0, 2.2); point.Cg = (float)Math.Pow(Convert.ToDouble(strs[6], System.Globalization.CultureInfo.InvariantCulture) / 255.0, 2.2); point.Cb = (float)Math.Pow(Convert.ToDouble(strs[7], System.Globalization.CultureInfo.InvariantCulture) / 255.0, 2.2); points.Add(point); } catch (FormatException e) { Console.WriteLine("ERROR: FormatException on line " + lineCounter.ToString() + "."); Console.WriteLine(e.Message); file.Close(); return; } catch (OverflowException e) { Console.WriteLine("ERROR: OverflowException on line " + lineCounter.ToString() + "."); Console.WriteLine(e.Message); file.Close(); return; } } else if (strs[0] == "BC") { if (len != 5) { Console.WriteLine("ERROR: Expected 4 values on line " + lineCounter.ToString() + ", but read " + (len - 1).ToString() + " values instead."); file.Close(); return; } try { for (var i = 1; i <= 4; ++i) { var index = Convert.ToInt32(strs[i]); if (index < 0) { Console.WriteLine("ERROR: Negative index on line " + lineCounter.ToString() + "."); file.Close(); return; } indices.Add(index); if (index > maxIndex) maxIndex = index; } } catch (FormatException e) { Console.WriteLine("ERROR: FormatException on line " + lineCounter.ToString() + "."); Console.WriteLine(e.Message); file.Close(); return; } catch (OverflowException e) { Console.WriteLine("ERROR: OverflowException on line " + lineCounter.ToString() + "."); Console.WriteLine(e.Message); file.Close(); return; } } else { Console.WriteLine("ERROR: Expected 'PT' or 'BC' as first string on line " + lineCounter.ToString() + ", but read '" + strs[0] + "' instead."); file.Close(); return; } } lineCounter++; } if (maxIndex > points.Count - 1) { Console.WriteLine("ERROR: Largest Index (" + maxIndex.ToString() + ") does not reference point."); file.Close(); return; } var indexLen = indices.Count; if (indexLen == 0) { Console.WriteLine("ERROR: File does not contain nodes."); file.Close(); return; } Console.WriteLine("SUCCESS: File '" + bezdatFilePath.ToString() + "' read."); file.Close(); var sPoints = new System.Collections.Generic.List<SplinePoint>(); var nodeCountPerTube = new System.Collections.Generic.List<int>(); nodeCountPerTube.Add(0); var currTubeId = 0; var tangentDiscCount = 0; for (var i = 0; i <= indexLen; i += 4) { var i0 = i != 0 ? i - 2 : i + 0; var i1 = i != 0 ? i - 1 : i + 1; var i2 = i != indexLen ? i + 0 : i0; var i3 = i != indexLen ? i + 1 : i1; var index0 = indices[i0]; var index1 = indices[i1]; var index2 = indices[i2]; var index3 = indices[i3]; var p0 = points[index0]; var p1 = points[index1]; var p2 = points[index2]; var p3 = points[index3]; var tan0 = new Point(); tan0.Px = (p1.Px - p0.Px) * 3.0f; tan0.Py = (p1.Py - p0.Py) * 3.0f; tan0.Pz = (p1.Pz - p0.Pz) * 3.0f; tan0.R = (p1.R - p0.R) * 3.0f; tan0.Cr = (p1.Cr - p0.Cr) * 3.0f; tan0.Cg = (p1.Cg - p0.Cg) * 3.0f; tan0.Cb = (p1.Cb - p0.Cb) * 3.0f; var tan1 = new Point(); tan1.Px = (p3.Px - p2.Px) * 3.0f; tan1.Py = (p3.Py - p2.Py) * 3.0f; tan1.Pz = (p3.Pz - p2.Pz) * 3.0f; tan1.R = (p3.R - p2.R) * 3.0f; tan1.Cr = (p3.Cr - p2.Cr) * 3.0f; tan1.Cg = (p3.Cg - p2.Cg) * 3.0f; tan1.Cb = (p3.Cb - p2.Cb) * 3.0f; var pTanDiff = Pow2(tan1.Px - tan0.Px) + Pow2(tan1.Py - tan0.Py) + Pow2(tan1.Pz - tan0.Pz); var rTanDiff = Pow2(tan1.R - tan0.R); //var cTanDiff = Pow2(tan1.Cr - tan0.Cr) + Pow2(tan1.Cg - tan0.Cg) + Pow2(tan1.Cb - tan0.Cb); var tanDiffDelta = 0.001; var deltaCond = pTanDiff < tanDiffDelta && rTanDiff < tanDiffDelta;// && cTanDiff < tanDiffDelta;// do not check color delta due to high quantization error? or errors in the data...*shrug* var sharedNodeCond = index1 == index2; var overwrittenNodesCond = index0 == index2 && index1 == index3; if (sharedNodeCond && !deltaCond) ++tangentDiscCount; if ((sharedNodeCond || overwrittenNodesCond) && deltaCond) { var sPoint = new SplinePoint(); sPoint.V = i != indexLen ? p2 : p3; sPoint.T = new Point(); sPoint.T.Px = (tan0.Px + tan1.Px) * 0.5f; sPoint.T.Py = (tan0.Py + tan1.Py) * 0.5f; sPoint.T.Pz = (tan0.Pz + tan1.Pz) * 0.5f; sPoint.T.R = (tan0.R + tan1.R) * 0.5f; sPoint.T.Cr = (tan0.Cr + tan1.Cr) * 0.5f; sPoint.T.Cg = (tan0.Cg + tan1.Cg) * 0.5f; sPoint.T.Cb = (tan0.Cb + tan1.Cb) * 0.5f; sPoints.Add(sPoint); ++nodeCountPerTube[currTubeId]; } else { var sPoint0 = new SplinePoint(); sPoint0.V = p1; sPoint0.T = tan0; sPoints.Add(sPoint0); ++nodeCountPerTube[currTubeId]; var sPoint1 = new SplinePoint(); sPoint1.V = p2; sPoint1.T = tan1; sPoints.Add(sPoint1); nodeCountPerTube.Add(1); ++currTubeId; } } Console.WriteLine("Number of Tangent Discontinuities: " + tangentDiscCount.ToString()); // create binary file { System.IO.BinaryWriter newFile = null; try { newFile = new System.IO.BinaryWriter(System.IO.File.Open(tubesFilePath, System.IO.FileMode.Create)); } catch (Exception e) { Console.WriteLine("ERROR: Could not create/open file '" + tubesFilePath.ToString() + "'."); Console.WriteLine(e.Message); return; } try { var formatVersion = 1; newFile.Write(formatVersion);// 1 x Int32 var tubeCount = nodeCountPerTube.Count; newFile.Write(tubeCount);// 1 x Int32 foreach (int nodeCount in nodeCountPerTube)// tubeCount x Int32 newFile.Write(nodeCount); var totalNodeCount = sPoints.Count; newFile.Write(totalNodeCount);// 1 x Int32 foreach (SplinePoint node in sPoints)// totalNodeCount x (3 + 1 + 3) * 2 x Single { newFile.Write(node.V.Px); newFile.Write(node.V.Py); newFile.Write(node.V.Pz); newFile.Write(node.V.R); newFile.Write(node.V.Cr); newFile.Write(node.V.Cg); newFile.Write(node.V.Cb); newFile.Write(node.T.Px); newFile.Write(node.T.Py); newFile.Write(node.T.Pz); newFile.Write(node.T.R); newFile.Write(node.T.Cr); newFile.Write(node.T.Cg); newFile.Write(node.T.Cb); } } catch (Exception e) { Console.WriteLine("ERROR: Failed to write value to file '" + tubesFilePath.ToString() + "'."); Console.WriteLine(e.Message); newFile.Close(); return; } Console.WriteLine("SUCCESS: File '" + tubesFilePath.ToString() + "' generated."); newFile.Close(); } // create plain text file for debugging purposes if(generatePlainTextVersion) { var tubesTxtFilePath = tubesFilePath + ".txt"; System.IO.StreamWriter newFile = null; try { newFile = new System.IO.StreamWriter(System.IO.File.Open(tubesTxtFilePath, System.IO.FileMode.Create)); } catch (Exception e) { Console.WriteLine("ERROR: Could not create/open file '" + tubesTxtFilePath.ToString() + "'."); Console.WriteLine(e.Message); return; } try { var formatVersion = 1; newFile.Write("Version: "); newFile.Write(formatVersion);// 1 x Int32 newFile.Write(Environment.NewLine); var tubeCount = nodeCountPerTube.Count; newFile.Write("Tube Count: "); newFile.Write(tubeCount);// 1 x Int32 newFile.Write(Environment.NewLine); newFile.Write("Node Counts per Tube: "); foreach (int nodeCount in nodeCountPerTube)// tubeCount x Int32 { newFile.Write(nodeCount); newFile.Write(" "); } newFile.Write(Environment.NewLine); var totalNodeCount = sPoints.Count; newFile.Write("Total Node Count: "); newFile.Write(totalNodeCount);// 1 x Int32 var n = 0; newFile.Write(Environment.NewLine); foreach (SplinePoint node in sPoints)// totalNodeCount x (3 + 1 + 3) * 2 x Single { newFile.Write(Environment.NewLine); newFile.Write("Node " + n.ToString() + ":"); newFile.Write(Environment.NewLine); ++n; newFile.Write(node.V.Px.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" "); newFile.Write(node.V.Py.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" "); newFile.Write(node.V.Pz.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(Environment.NewLine); newFile.Write(node.V.R.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(Environment.NewLine); newFile.Write(node.V.Cr.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" "); newFile.Write(node.V.Cg.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" "); newFile.Write(node.V.Cb.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(Environment.NewLine); newFile.Write(node.T.Px.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" "); newFile.Write(node.T.Py.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" "); newFile.Write(node.T.Pz.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(Environment.NewLine); newFile.Write(node.T.R.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(Environment.NewLine); newFile.Write(node.T.Cr.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" "); newFile.Write(node.T.Cg.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" "); newFile.Write(node.T.Cb.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(Environment.NewLine); } } catch (Exception e) { Console.WriteLine("ERROR: Failed to write value to file '" + tubesTxtFilePath.ToString() + "'."); Console.WriteLine(e.Message); newFile.Close(); return; } Console.WriteLine("SUCCESS: File '" + tubesTxtFilePath.ToString() + "' generated."); newFile.Close(); } }
void PointsGUI() { CustomPathGenerator generator = (CustomPathGenerator)target; generator.customPathType = (Spline.Type)EditorGUILayout.EnumPopup("Custom Path Type", generator.customPathType); if (generator.points.Length >= 4) { generator.loop = EditorGUILayout.Toggle("Loop", generator.loop); } else { generator.loop = false; } string[] options = new string[(generator.loop ? generator.points.Length - 1 : generator.points.Length) + 1]; for (int i = 0; i < options.Length - 1; i++) { options[i + 1] = "Point " + (i + 1); } options[0] = "- None -"; EditorGUILayout.BeginHorizontal(); selectedPoint = EditorGUILayout.Popup("Select Point", selectedPoint + 1, options) - 1; if ((!generator.loop && generator.points.Length >= 1) || (generator.loop && generator.points.Length > 4)) { if (GUILayout.Button("X", GUILayout.Width(20))) { ArrayUtility.RemoveAt(ref generator.points, selectedPoint); selectedPoint--; } } EditorGUILayout.EndHorizontal(); if (selectedPoint >= 0 && selectedPoint < generator.points.Length) { SplinePoint avgPoint = generator.points[selectedPoint]; avgPoint.SetPosition(EditorGUILayout.Vector3Field("Position", avgPoint.position)); if (generator.customPathType == Splines.Spline.Type.Bezier) { EditorGUILayout.Space(); avgPoint.type = (SplinePoint.Type)EditorGUILayout.EnumPopup("Tangents Type", avgPoint.type); avgPoint.SetTangent2Position(EditorGUILayout.Vector3Field("Front Tangent", avgPoint.tangent2)); avgPoint.SetTangentPosition(EditorGUILayout.Vector3Field("Back Tangent", avgPoint.tangent)); EditorGUILayout.Space(); } else { avgPoint.tangent = avgPoint.position; avgPoint.tangent2 = avgPoint.position; } avgPoint.normal = EditorGUILayout.Vector3Field("Normal", avgPoint.normal); avgPoint.normal.Normalize(); EditorGUIUtility.labelWidth = 0f; avgPoint.size = EditorGUILayout.FloatField("Size", avgPoint.size); avgPoint.color = EditorGUILayout.ColorField("Color", avgPoint.color); if (generator.loop) { generator.points[generator.points.Length - 1] = generator.points[0]; } generator.points[selectedPoint] = avgPoint; } if (GUILayout.Button("Create Point")) { SplinePoint newPoint = new SplinePoint(); newPoint.color = Color.white; newPoint.size = 1f; newPoint.normal = Vector3.up; ArrayUtility.Add(ref generator.points, newPoint); selectedPoint = generator.points.Length - 1; } }