private float ShowMidpointControls(Ferr2DPath aPath, int i, PathEditorUtil.Selection aSelection, Matrix4x4 aTransform, SerializedProperty aPathProp, float aCurrDistance) { EventType eType = Event.current.type; // calculate distance data for finding the midpoint float segmentDistance = aPath.GetDistanceBetween(i, PathUtil.WrapIndex(i + 1, aPath.Count, aPath.Closed)); float nextDistance = aCurrDistance + segmentDistance; float midDist = aCurrDistance + (segmentDistance) / 2; // if we have no segment on the control vert, skip this midpoint if (aPath.Count <= 1 || (i == aPath.Count - 1 && !aPath.Closed)) { return(nextDistance); } // find the midpoint of this line Vector2 midPoint = aPath.GetPointAtDistance(midDist); Vector2 midNormal = aPath.GetNormalAtDistance(midDist); Vector3 midWorldPoint = aTransform.MultiplyPoint(midPoint); Vector3 midWorldNormal = aTransform.MultiplyVector(midNormal); float midSize = eType == EventType.Layout || eType == EventType.Repaint ? HandleUtility.GetHandleSize(midWorldPoint) : 0; // edge override button int direction = aPath.GetData(i).directionOverride; if (terrain.EdgeMode != Ferr2D_SectionMode.None && (i == activeSegment || aSelection.IsSegmentSelected(i, aPath.Count, aPath.Closed) || direction != (int)Ferr2DT_TerrainDirection.None)) { if (Event.current.alt) { if (direction != (int)Ferr2DT_TerrainDirection.None && Handles.Button(midWorldPoint + midWorldNormal * midSize * sizeLargeHandle * 2, Quaternion.identity, midSize * sizeSmallHandle, midSize * sizeSmallHandle, Ferr2DT_Caps.CapDotReset)) { aSelection.EachSegment(i, aPath.Count, aPath.Closed, id => { SerializedProperty overrideProp = aPathProp.FindPropertyRelative("_data").GetArrayElementAtIndex(id).FindPropertyRelative("directionOverride"); overrideProp.intValue = (int)Ferr2DT_TerrainDirection.None; }); } } else { if (Handles.Button(midWorldPoint + midWorldNormal * midSize * sizeLargeHandle * 2, Quaternion.identity, midSize * sizeSmallHandle, midSize * sizeSmallHandle, Ferr2DT_Caps.GetEdgeCap(direction))) { CycleEdgeOverride(aPathProp, i); SerializedProperty cycledOverride = aPathProp.FindPropertyRelative("_data").GetArrayElementAtIndex(i).FindPropertyRelative("directionOverride"); aSelection.EachSegment(i, aPath.Count, aPath.Closed, id => { SerializedProperty overrideProp = aPathProp.FindPropertyRelative("_data").GetArrayElementAtIndex(id).FindPropertyRelative("directionOverride"); overrideProp.intValue = cycledOverride.intValue; }); } } } // new point button if (!Event.current.alt && i == activeSegment && Handles.Button(midWorldPoint, Quaternion.identity, midSize * sizeLargeHandle, midSize * sizeLargeHandle, Ferr2DT_Caps.CapDotPlus)) { PathEditorUtil.AddPoint(aPathProp, midPoint, i + 1); ProcessNewPoint(aPathProp, i + 1); } return(nextDistance); }
private void FindActiveControls(Ferr2DPath aPath, Matrix4x4 aTransform, Matrix4x4 aInvTransform) { if (Event.current.type == EventType.MouseMove) { Ray r = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); Plane p = new Plane(aTransform.MultiplyVector(Vector3.forward), aTransform.MultiplyPoint(Vector3.zero)); float dist = 0; if (p.Raycast(r, out dist)) { Vector2 mousePoint = aInvTransform.MultiplyPoint(r.GetPoint(dist)); int newSegment = aPath.GetClosestSegment(mousePoint); if (newSegment != activeSegment) { activeSegment = newSegment; SceneView.RepaintAll(); } int newPoint = aPath.GetClosestControlPoint(mousePoint); if (newPoint != activePoint) { activePoint = newPoint; SceneView.RepaintAll(); } } } }
private void ShowPathGUI(Transform aTransform, Ferr2DPath aPath, SerializedProperty aPathProp) { EventType eType = Event.current.type; Matrix4x4 mat = aTransform.localToWorldMatrix; // show the path and all its standard controls PathEditorUtil.OnSceneGUI(aTransform.localToWorldMatrix, aTransform.worldToLocalMatrix, aPathProp, aPath, true, ProcessNewPoint, ProcessRemovePoint, Path2D.Plane.XY, Ferr2DT_Menu.PathSnapMode, Ferr2DT_Menu.SmartSnap?Ferr2DT_Menu.SmartSnapDist:0, KeyCode.C, visuals); PathEditorUtil.Selection selection = PathEditorUtil.GetSelection(aPath); // find which segments and points are active FindActiveControls(aPath, mat, aTransform.worldToLocalMatrix); if (Ferr2DT_SceneOverlay.segmentLockMode) { ShowTexSegmentSelect(aPath, aPathProp, mat); } else { float currDistance = 0; for (int i = 0; i < aPath.Count; i++) { // show all the data at the control points ShowPointControls(aPath, i, selection, mat, aPathProp); // show midpoint controls currDistance = ShowMidpointControls(aPath, i, selection, mat, aPathProp, currDistance); } } // drag select has to happen last, otherwise it steals control ahead of the other handles ShowDragSelect(aPath, mat); }
private void ShowPointControls(Ferr2DPath aPath, int i, PathEditorUtil.Selection aSelection, Matrix4x4 aTransform, SerializedProperty aPathProp) { EventType eType = Event.current.type; Ferr2D_PointData pointData = aPath.GetData(i); Vector2 point = aPath[i]; Vector2 pointNormal = aPath.GetNormal(i); Vector3 pointWorld = aTransform.MultiplyPoint(point); Vector3 pointWorldNormal = aTransform.MultiplyVector(pointNormal); float pointSize = eType == EventType.Layout || eType == EventType.Repaint ? HandleUtility.GetHandleSize(pointWorld) : 0; // point scale button if (terrain.EdgeMode != Ferr2D_SectionMode.None && (i == activePoint || aSelection.IsSelected(i) || pointData.scale != 1)) { Vector3 scaleStart = pointWorld + pointWorldNormal * (visuals.sizeVertex + sizeSmallHandle) * pointSize; Vector3 scalePos = scaleStart + ((pointData.scale - 0.5f) * 3f) * pointWorldNormal; if (Event.current.alt) { // reset scale if (pointData.scale != 1 && Handles.Button(scalePos, Quaternion.identity, pointSize * sizeSmallHandle, pointSize * sizeSmallHandle, Ferr2DT_Caps.CapDotReset)) { aSelection.Each(i, id => { SerializedProperty scaleProp = aPathProp.FindPropertyRelative("_data").GetArrayElementAtIndex(id).FindPropertyRelative("scale"); scaleProp.floatValue = 1; }); } } else { Vector2 screenNormal = HandleUtility.WorldToGUIPoint(pointWorld + pointWorldNormal) - HandleUtility.WorldToGUIPoint(pointWorld); screenNormal.Normalize(); Vector3 move = Handles.FreeMoveHandle(scalePos, Quaternion.identity, pointSize * sizeSmallHandle, Vector3.zero, Ferr2DT_Caps.GetScaleCap(screenNormal)); if (move != scalePos) { move = PathUtil.GetClosetPointOnLine(scaleStart, scaleStart + pointWorldNormal * 3, move, true); float finalScale = 0.5f + (scaleStart - move).magnitude / 3f; float delta = finalScale - pointData.scale; aSelection.Each(i, id => { SerializedProperty scaleProp = aPathProp.FindPropertyRelative("_data").GetArrayElementAtIndex(id).FindPropertyRelative("scale"); scaleProp.floatValue += delta; }); } } } // show index numbers if (Ferr2DT_SceneOverlay.showIndices) { Vector2 pt = HandleUtility.WorldToGUIPoint(pointWorld - pointWorldNormal * pointSize * sizeLargeHandle * 2); Rect r = new Rect(pt.x - 15, pt.y - EditorGUIUtility.singleLineHeight * 0.5f, 30, EditorGUIUtility.singleLineHeight); Handles.BeginGUI(); GUI.Label(r, i.ToString(), PathEditorUtil.CenteredShadowStyle); GUI.Label(r, i.ToString(), PathEditorUtil.CenteredLabelStyle); Handles.EndGUI(); } }
private void ShowDragSelect(Ferr2DPath aPath, Matrix4x4 aTransform) { if (!Ferr2DT_Menu.DragSelect) { return; } // manually make a move widget, since we have to override Unity's widget Vector3 center = Vector3.zero; if (Tools.pivotMode == PivotMode.Center) { center = PathUtil.Average(aPath.GetPathRaw()); } Vector3 newPos = Handles.DoPositionHandle(terrain.transform.position + center, Quaternion.identity) - center; if (newPos != terrain.transform.position) { Undo.RecordObject(terrain.transform, "Move Terrain Object"); terrain.transform.position = newPos; } // execute the drag-select code PathEditorUtil.DoDragSelect(aTransform, aPath, new Rect(0, EditorGUIUtility.singleLineHeight, Screen.width, Screen.height - EditorGUIUtility.singleLineHeight), visuals); }
public void LegacyUpgrade() { if (!IsLegacy) { return; } #if UNITY_EDITOR UnityEditor.Undo.RecordObject(gameObject, "Upgrade Ferr2D Terrain"); #endif Ferr2D_Path oldPath = GetComponent <Ferr2D_Path>(); MatchOverrides(); // upgrade the path pathData = new Ferr2DPath(); pathData.Closed = oldPath.closed; for (int i = 0; i < oldPath.pathVerts.Count; i++) { int next = Ferr.PathUtil.WrapIndex(i - 1, Path.Count, Path.closed); Ferr.PointType pointType = Ferr.PointType.Sharp; if (smoothPath) { Ferr2DT_TerrainDirection prevSegmentDirection = Ferr2D_Path.GetDirection(Path.pathVerts, next, fill == Ferr2DT_FillMode.InvertedClosed, Path.closed, directionOverrides); Ferr2DT_TerrainDirection nextSegmentDirection = Ferr2D_Path.GetDirection(Path.pathVerts, i, fill == Ferr2DT_FillMode.InvertedClosed, Path.closed, directionOverrides); if (prevSegmentDirection == nextSegmentDirection) { pointType = Ferr.PointType.Auto; } } Ferr2D_PointData data = new Ferr2D_PointData(); data.scale = vertScales[next]; data.directionOverride = (int)directionOverrides[next]; data.cutOverrides = cutOverrides[next].data; pathData.Add(oldPath.pathVerts[i], data, pointType); } pathData.ReverseSelf(); pathData.SetDirty(); // remove old path values directionOverrides = null; cutOverrides = null; vertScales = null; // upgrade collider settings if (createCollider) { if (useEdgeCollider) { colliderMode = Ferr2D_ColliderMode.Edge2D; } else if (create3DCollider) { colliderMode = Ferr2D_ColliderMode.Mesh3D; } else { colliderMode = Ferr2D_ColliderMode.Polygon2D; } } else { colliderMode = Ferr2D_ColliderMode.None; } // upgrade the fill settings switch (fill) { case Ferr2DT_FillMode.None: edgeMode = Ferr2D_SectionMode.Normal; fillMode = Ferr2D_SectionMode.None; break; case Ferr2DT_FillMode.Closed: edgeMode = Ferr2D_SectionMode.Normal; fillMode = Ferr2D_SectionMode.Normal; break; case Ferr2DT_FillMode.InvertedClosed: edgeMode = Ferr2D_SectionMode.Invert; fillMode = Ferr2D_SectionMode.Invert; break; case Ferr2DT_FillMode.FillOnlyClosed: edgeMode = Ferr2D_SectionMode.None; fillMode = Ferr2D_SectionMode.Normal; break; case Ferr2DT_FillMode.Skirt: edgeMode = Ferr2D_SectionMode.Normal; fillMode = Ferr2D_SectionMode.Normal; useSkirt = true; break; case Ferr2DT_FillMode.FillOnlySkirt: edgeMode = Ferr2D_SectionMode.None; fillMode = Ferr2D_SectionMode.Normal; useSkirt = true; break; } isLegacy = false; #if UNITY_EDITOR UnityEditor.Undo.DestroyObjectImmediate(oldPath); #else Destroy(oldPath); #endif Build(true); #if UNITY_EDITOR UnityEditor.SceneView.RepaintAll(); #endif }
private void Start() { terrain = GetComponent <Ferr2DT_PathTerrain>(); ferr2DPath = terrain.PathData; List <Vector2> rawPath = ferr2DPath.GetPathRaw(); List <Vector2> finalPath = ferr2DPath.GetFinalPath(); //List<FloorNode> floorNodeList = new List<FloorNode>(finalPath.Count); FloorNode[] floorNodeArray = new FloorNode[finalPath.Count]; // Create Walk Nodes for (int i = 0; i < finalPath.Count; i++) { Ferr2DT_TerrainDirection dir = Ferr2DT_PathTerrain.GetSegmentDirection(ferr2DPath, i); if (dir == Ferr2DT_TerrainDirection.Top) { if (i == finalPath.Count - 1) { floorNodeArray[i] = InstantiateFloorNode(finalPath[0], finalPath[i]); } else { floorNodeArray[i] = InstantiateFloorNode(finalPath[i + 1], finalPath[i]); } floorNodeArray[i].owner = this; ownedFloorNodes.Add(floorNodeArray[i]); } } // Check if there are any consecutive walk nodes // if so, set them as neighbors for (int i = 1; i < floorNodeArray.Length; i++) { if (floorNodeArray[i] != null && floorNodeArray[i - 1] != null) { // found consecutive walk nodes // set their neighboringness with regards to their x-coordinate if (floorNodeArray[i - 1].gameObject.transform.position.x < floorNodeArray[i].gameObject.transform.position.x) { floorNodeArray[i - 1].SetRightNeighbor(floorNodeArray[i]); floorNodeArray[i].SetLeftNeighbor(floorNodeArray[i - 1]); } else { floorNodeArray[i].SetRightNeighbor(floorNodeArray[i - 1]); floorNodeArray[i - 1].SetLeftNeighbor(floorNodeArray[i]); } } } // the edge case if (floorNodeArray[0] != null && floorNodeArray[floorNodeArray.Length - 1] != null) { if (floorNodeArray[0].gameObject.transform.position.x < floorNodeArray[floorNodeArray.Length - 1].gameObject.transform.position.x) { floorNodeArray[0].SetRightNeighbor(floorNodeArray[floorNodeArray.Length - 1]); floorNodeArray[floorNodeArray.Length - 1].SetLeftNeighbor(floorNodeArray[0]); } else { floorNodeArray[floorNodeArray.Length - 1].SetRightNeighbor(floorNodeArray[0]); floorNodeArray[0].SetLeftNeighbor(floorNodeArray[floorNodeArray.Length - 1]); } } foreach (FloorNode w in floorNodeArray) { if (w != null) { w.CheckIntersections(); } } }
private void ShowTexSegmentSelect(Ferr2DPath aPath, SerializedProperty aPathProp, Matrix4x4 aTransform) { // calculate segment information for displaying the handles correctly List <Ferr2DT_PathTerrain.EdgeSegment> segments = Ferr2DT_PathTerrain.EdgeSegment.CreateEdgeSegments(aPath, terrain.splitCorners); bool invert = terrain.EdgeMode == Ferr2D_SectionMode.Invert; Vector2 upUV = terrain.UnitsPerUV; for (int i = 0; i < segments.Count; i++) { // get our segment data, and see if we have any data to override with var edgeSegment = segments[i]; edgeSegment.direction = invert ? Ferr2DT_PathTerrain.Invert(edgeSegment.direction) : edgeSegment.direction; var edgeData = terrain.TerrainMaterial.GetDescriptor(edgeSegment.direction); if (edgeData.BodyCount < 2) { continue; } bool rightInner = edgeSegment.path.GetInteriorAngle(edgeSegment.start) > 180; float rightOff = edgeData.GetRightCapOffset(invert? !rightInner:rightInner, upUV); // calculate all the texture segments present List <int> texSources = new List <int>(); float scale = 0; List <int> texSegments = terrain.CreateLineList(edgeSegment, out scale, texSources); // now go and add handles for all the texture segments for (int t = 0; t < texSegments.Count; t++) { // find handle location float segDist = TexDistAtSegment(edgeSegment, edgeData, texSegments, t) * scale; Vector3 pt = aTransform.MultiplyPoint(aPath.GetPointAtDistance(edgeSegment.startDistance - rightOff + segDist)); float size = HandleUtility.GetHandleSize(pt); // figure out what our data says about this segment, if anything int cutPointId = texSources[t * 2]; int cutId = texSources[t * 2 + 1]; int cutValue = 0; var cutOverrides = aPath.GetData(cutPointId).cutOverrides; if (cutOverrides != null && cutOverrides.Count > cutId) { cutValue = cutOverrides[cutId]; } // and execute the handles if (Event.current.alt) { if (cutValue != 0 && Handles.Button(pt, Quaternion.identity, size * sizeSmallHandle, size * sizeSmallHandle, Ferr2DT_Caps.CapDotReset)) { SerializedProperty cutProp = aPathProp.FindPropertyRelative("_data").GetArrayElementAtIndex(cutPointId).FindPropertyRelative("cutOverrides"); SerializedProperty segCutProperty = cutProp.GetArrayElementAtIndex(cutId); segCutProperty.intValue = 0; } } else { if (Handles.Button(pt, Quaternion.identity, size * sizeSmallHandle, size * sizeSmallHandle, Ferr2DT_Caps.GetNumberCap(cutValue))) { SerializedProperty cutProp = aPathProp.FindPropertyRelative("_data").GetArrayElementAtIndex(cutPointId).FindPropertyRelative("cutOverrides"); while (cutProp.arraySize <= cutId) { cutProp.arraySize += 1; cutProp.GetArrayElementAtIndex(cutProp.arraySize - 1).intValue = 0; } while (cutProp.arraySize > texSegments.Count) { cutProp.arraySize--; } SerializedProperty segCutProperty = cutProp.GetArrayElementAtIndex(cutId); segCutProperty.intValue = (segCutProperty.intValue + 1) % (edgeData.BodyCount + 1); } } } } }