192 lines
7.6 KiB
C#
192 lines
7.6 KiB
C#
#if UNITY_EDITOR
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using UnityEditor;
|
|
using System.Collections.Generic;
|
|
|
|
namespace GSpawn
|
|
{
|
|
public class ObjectSelectionSegments : ObjectSelectionShape
|
|
{
|
|
private enum State
|
|
{
|
|
Idle = 0,
|
|
Selecting
|
|
}
|
|
|
|
private State _state = State.Idle;
|
|
private List<Vector3> _gridCellPoints = new List<Vector3>();
|
|
private HashSet<GameObject> _overlappedSet = new HashSet<GameObject>();
|
|
private SceneRaycastFilter _raycastFilter = new SceneRaycastFilter();
|
|
private ObjectOverlapConfig _overlapConfig = new ObjectOverlapConfig();
|
|
private ObjectOverlapFilter _overlapFilter = new ObjectOverlapFilter();
|
|
private ObjectBounds.QueryConfig _boundQConfig = new ObjectBounds.QueryConfig();
|
|
private List<GameObject> _objectOverlapResult = new List<GameObject>();
|
|
private LineStrip _lineStrip = new LineStrip();
|
|
|
|
public override bool selecting { get { return _state == State.Selecting; } }
|
|
public override Type shapeType { get { return Type.Segments; } }
|
|
|
|
public ObjectSelectionSegments()
|
|
{
|
|
_raycastFilter.objectTypes = GameObjectType.Mesh | GameObjectType.Terrain | GameObjectType.Sprite;
|
|
_boundQConfig.objectTypes = GameObjectType.Mesh | GameObjectType.Sprite;
|
|
_overlapFilter.objectTypes = GameObjectType.Mesh | GameObjectType.Sprite;
|
|
_overlapFilter.customFilter = (go) => { return LayerEx.isPickingEnabled(go.layer) && !SceneVisibilityManager.instance.IsPickingDisabled(go); };
|
|
|
|
_overlapConfig.requireFullOverlap = false;
|
|
_overlapConfig.prefabMode = ObjectOverlapPrefabMode.PrefabInstanceRootIfPossible;
|
|
}
|
|
|
|
public override void cancel()
|
|
{
|
|
_lineStrip.clearKeepLastPoint();
|
|
updateState();
|
|
}
|
|
|
|
public void removeLastNode()
|
|
{
|
|
if (_lineStrip.numPoints > 1)
|
|
{
|
|
_lineStrip.removeLastPoint();
|
|
updateState();
|
|
}
|
|
}
|
|
|
|
protected override void update()
|
|
{
|
|
if (!ObjectSelection.instance.multiSelectEnabled)
|
|
{
|
|
_lineStrip.clearKeepLastPoint();
|
|
updateState();
|
|
return;
|
|
}
|
|
|
|
Event e = Event.current;
|
|
if (e.type == EventType.MouseMove) pickPoint();
|
|
else
|
|
if (e.type == EventType.MouseDown && !e.alt)
|
|
{
|
|
if (e.button == (int)MouseButton.LeftMouse)
|
|
{
|
|
if (FixedShortcuts.structureBuild_EnableCommitOnLeftClick(e))
|
|
{
|
|
_lineStrip.clearKeepLastPoint();
|
|
e.disable();
|
|
}
|
|
else
|
|
{
|
|
if (_lineStrip.numPoints == 1) _undoConfig.groupIndex = Undo.GetCurrentGroup();
|
|
_lineStrip.duplicateLastPoint();
|
|
e.disable();
|
|
}
|
|
}
|
|
else
|
|
if (e.button == (int)MouseButton.RightMouse)
|
|
{
|
|
if (FixedShortcuts.selectionSegments_EnableStepBack(e)) removeLastNode();
|
|
}
|
|
}
|
|
else
|
|
if (e.type == EventType.KeyDown)
|
|
{
|
|
if (FixedShortcuts.cancelAction(e))
|
|
{
|
|
_lineStrip.clearKeepLastPoint();
|
|
e.disable();
|
|
}
|
|
}
|
|
|
|
updateState();
|
|
}
|
|
|
|
protected override void detectOverlappedObjects()
|
|
{
|
|
_overlappedObjects.Clear();
|
|
_overlappedSet.Clear();
|
|
if (!ObjectSelection.instance.multiSelectEnabled) return;
|
|
|
|
const float segmentThickness = 1e-7f;
|
|
|
|
int numPoints = _lineStrip.numPoints;
|
|
for (int segmentIndex = 0; segmentIndex < numPoints - 1; ++segmentIndex)
|
|
{
|
|
Vector3 firstPt = _lineStrip.getPoint(segmentIndex);
|
|
Vector3 secondPt = _lineStrip.getPoint(segmentIndex + 1);
|
|
|
|
OBB overlapOBB = OBB.createFromSegment(firstPt, secondPt, segmentThickness);
|
|
if (!overlapOBB.isValid) overlapOBB = new OBB(firstPt, Vector3Ex.create(segmentThickness), Quaternion.identity);
|
|
if (PluginScene.instance.overlapBox(overlapOBB, _overlapFilter, _overlapConfig, _objectOverlapResult))
|
|
{
|
|
foreach (var go in _objectOverlapResult)
|
|
{
|
|
// Note: We need the set to check for duplicates because segments may overlap
|
|
// or, in any case, they may share objects.
|
|
if (!_overlappedSet.Contains(go))
|
|
{
|
|
_overlappedObjects.Add(go);
|
|
_overlappedSet.Add(go);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_overlappedSet.Clear();
|
|
}
|
|
|
|
protected override void draw()
|
|
{
|
|
_lineStrip.segmentColor = ObjectSelectionPrefs.instance.selSegmentsSegmentColor;
|
|
_lineStrip.tickColor = ObjectSelectionPrefs.instance.selSegmentsTickColor;
|
|
_lineStrip.tickSize = ObjectSelectionPrefs.instance.selSegmentsTickSize;
|
|
_lineStrip.draw();
|
|
}
|
|
|
|
private void updateState()
|
|
{
|
|
if (_lineStrip.numPoints > 1) _state = State.Selecting;
|
|
else _state = State.Idle;
|
|
}
|
|
|
|
private void pickPoint()
|
|
{
|
|
var rayHit = PluginScene.instance.raycastClosest(PluginCamera.camera.getCursorRay(), _raycastFilter, ObjectRaycastConfig.defaultConfig);
|
|
if (!rayHit.anyHit) return;
|
|
|
|
Vector3 pt = Vector3.zero;
|
|
if (rayHit.wasObjectHit && rayHit.wasGridHit)
|
|
{
|
|
if (rayHit.gridHit.hitEnter < rayHit.objectHit.hitEnter &&
|
|
Mathf.Abs(rayHit.gridHit.hitEnter - rayHit.objectHit.hitEnter) > 1e-4f) pt = pointFromGridHit(rayHit.gridHit);
|
|
else pt = pointFromObjectHit(rayHit.objectHit);
|
|
}
|
|
else if (rayHit.wasObjectHit) pt = pointFromObjectHit(rayHit.objectHit);
|
|
else if (rayHit.wasGridHit) pt = pointFromGridHit(rayHit.gridHit);
|
|
|
|
_lineStrip.replaceLastPointOrAdd(pt);
|
|
}
|
|
|
|
private Vector3 pointFromObjectHit(ObjectRayHit objectHit)
|
|
{
|
|
GameObjectType objectType = GameObjectDataDb.instance.getGameObjectType(objectHit.hitObject);
|
|
if (objectType == GameObjectType.Terrain) return objectHit.hitPoint;
|
|
else
|
|
{
|
|
OBB worldOBB = ObjectBounds.calcWorldOBB(objectHit.hitObject, _boundQConfig);
|
|
if (worldOBB.isValid) return worldOBB.center;
|
|
}
|
|
|
|
return Vector3.zero;
|
|
}
|
|
|
|
private Vector3 pointFromGridHit(GridRayHit gridHit)
|
|
{
|
|
gridHit.hitGrid.calcCellCenterAndCorners(gridHit.hitCell, true, _gridCellPoints);
|
|
int closestPtIndex = Vector3Ex.findIndexOfPointClosestToPoint(_gridCellPoints, gridHit.hitPoint);
|
|
if (closestPtIndex >= 0) return _gridCellPoints[closestPtIndex];
|
|
|
|
return Vector3.zero;
|
|
}
|
|
}
|
|
}
|
|
#endif |