BITFALL/Assets/GSpawn - Level Designer/Scripts/Level Design/Gizmos/Object Extrude Gizmos/ObjectExtrudeGizmo.cs

858 lines
38 KiB
C#

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using UnityEngine.UIElements;
namespace GSpawn
{
public class ObjectExtrudeGizmo : PluginGizmo
{
public delegate void VerticalAxisExtrudeSpawnHandler (ObjectExtrudeGizmo extrudeGizmo, List<GameObject> spawnedParents);
public delegate void ExtrudeSpawnHandler (ObjectExtrudeGizmo extrudeGizmo, List<GameObject> spawnedParents);
public event VerticalAxisExtrudeSpawnHandler verticalAxisExtrudeSpawn;
public event ExtrudeSpawnHandler extrudeSpawn;
private class Slider
{
public Vector3 position;
public Vector3 direction;
public int controlId;
public bool visible;
}
private class SglAxisSlider : Slider
{
public enum Id
{
Right = 0,
Left,
Top,
Bottom,
Forward,
Back
}
public float dragSign;
public Id sliderId;
public int axis;
public bool isXAxis { get { return axis == 0; } }
public bool isYAxis { get { return axis == 1; } }
public bool isZAxis { get { return axis == 2; } }
public Vector3 dragDirection { get { return direction * dragSign; } }
}
private class DblAxisSlider : Slider
{
public enum Id
{
RightForward = 0,
RightBack,
LeftBack,
LeftForward,
TopRight,
BottomRight,
BottomLeft,
TopLeft,
ForwardTop,
ForwardBottom,
BackBottom,
BackTop
}
public float dragSign0;
public float dragSign1;
public int axis0;
public int axis1;
public Id sliderId;
public bool isXZAxis { get { return axis0 == 0 && axis1 == 2; } }
public bool isYXAxis { get { return axis0 == 1 && axis1 == 0; } }
public bool isZYAxis { get { return axis0 == 2 && axis1 == 1; } }
}
private static readonly float _minBoxSize = 1e-6f;
private Vector3 _dragStartPosition;
private SglAxisSlider[] _sglAxisSliders = new SglAxisSlider[6];
private DblAxisSlider[] _dblAxisSliders = new DblAxisSlider[12];
private SglAxisSlider _hoveredSglAxisSlider = null;
private DblAxisSlider _hoveredDblAxisSlider = null;
private ObjectGrid3D _grid = new ObjectGrid3D();
private Vector3Int _targetObjectsCellCoords = Vector3Int.zero;
private bool _spawnOnRepaint;
private IEnumerable<GameObject> _targetObjects;
private List<GameObject> _targetParents = new List<GameObject>();
private List<GameObject> _spawnedParents = new List<GameObject>();
private Dictionary<GameObject, Vector3> _spawnAnchorMap = new Dictionary<GameObject, Vector3>();
[NonSerialized]
private ObjectBounds.QueryConfig _targetBoundsQConfig = new ObjectBounds.QueryConfig()
{
objectTypes = GameObjectType.Sprite | GameObjectType.Mesh | GameObjectType.Terrain,
includeInactive = false,
includeInvisible = false,
volumelessSize = Vector3.zero
};
[NonSerialized]
private ObjectBounds.QueryConfig _overlapBoundsQConfig = new ObjectBounds.QueryConfig()
{
objectTypes = GameObjectType.Sprite | GameObjectType.Mesh | GameObjectType.Terrain,
includeInactive = false,
includeInvisible = false,
volumelessSize = Vector3.zero
};
[NonSerialized]
private ObjectOverlapFilter _overlapFilter = new ObjectOverlapFilter();
[NonSerialized]
private TerrainObjectOverlapFilter _terrainOverlapFilter = new TerrainObjectOverlapFilter();
[SerializeField]
private Vector3 _boxSize = Vector3.zero;
[SerializeField]
private ObjectExtrudeSpace _lastExtrudeSpace;
[NonSerialized]
private ObjectExtrudeGizmoSettings _sharedSettings;
[SerializeField]
private ObjectProjectionSettings _terrainProjectionSettings;
[NonSerialized]
private List<GameObject> _verticalAxisObjectsBuffer = new List<GameObject>();
[NonSerialized]
private TerrainCollection _terrains = new TerrainCollection();
private ObjectProjectionSettings terrainProjectionSettings
{
get
{
if (_terrainProjectionSettings == null)
{
_terrainProjectionSettings = CreateInstance<ObjectProjectionSettings>();
UndoEx.saveEnabledState();
UndoEx.enabled = false;
_terrainProjectionSettings.halfSpace = ObjectProjectionHalfSpace.InFront;
_terrainProjectionSettings.embedInSurface = true;
_terrainProjectionSettings.projectAsUnit = false;
_terrainProjectionSettings.alignAxis = false;
UndoEx.restoreEnabledState();
}
return _terrainProjectionSettings;
}
}
public Vector3 boxCenter { get { return position; } }
public Quaternion boxRotation { get { return rotation; } }
public Vector3 boxSize { get { return _boxSize; } }
public Vector3 boxExtents { get { return _boxSize * 0.5f; } }
public Vector3Int numExtrudeCells { get { return extruding ? _grid.numCells : Vector3Int.zero; } }
public bool extruding { get { return _hoveredSglAxisSlider != null || _hoveredDblAxisSlider != null; } }
public ObjectExtrudeGizmoSettings sharedSettings { get { return _sharedSettings; } set { _sharedSettings = value; } }
public ObjectExtrudeGizmo()
{
for (int index = 0; index < _sglAxisSliders.Length; ++index)
_sglAxisSliders[index] = new SglAxisSlider();
for (int index = 0; index < _dblAxisSliders.Length; ++index)
_dblAxisSliders[index] = new DblAxisSlider();
int axis = 0;
var sglSliderIds = Enum.GetValues(typeof(SglAxisSlider.Id));
foreach(var sliderId in sglSliderIds)
{
_sglAxisSliders[(int)sliderId].axis = axis / 2;
_sglAxisSliders[(int)sliderId].sliderId = (SglAxisSlider.Id)sliderId;
++axis;
}
var dblSliderIds = Enum.GetValues(typeof(DblAxisSlider.Id));
int[] axesPairs = new int[] {0, 2, 0, 2, 0, 2, 0, 2, 1, 0, 1, 0, 1, 0, 1, 0, 2, 1, 2, 1, 2, 1, 2, 1};
int sliderIndex = 0;
foreach(var sliderId in dblSliderIds)
{
var slider = _dblAxisSliders[(int)sliderId];
slider.sliderId = (DblAxisSlider.Id)sliderId;
slider.axis0 = axesPairs[sliderIndex * 2];
slider.axis1 = axesPairs[sliderIndex * 2 + 1];
++sliderIndex;
}
_grid.isCellMasked = isGridCellMasked;
_overlapFilter.objectTypes = GameObjectType.Mesh | GameObjectType.Sprite;
_overlapFilter.customFilter = (GameObject go) => { return !go.isTerrainMesh() && !go.isSphericalMesh(); };
}
public void getTargetParents(List<GameObject> targetParents)
{
targetParents.Clear();
GameObjectEx.getParents(_targetObjects, targetParents);
}
public void getExtrudeCellsOBBs(List<OBB> obbs)
{
obbs.Clear();
if (!_grid.hasCells) return;
for (int x = 0; x < _grid.numCellsX; ++x)
{
for (int y = 0; y < _grid.numCellsY; ++y)
{
for (int z = 0; z < _grid.numCellsZ; ++z)
{
obbs.Add(_grid.calcCellOBB(x, y, z));
}
}
}
}
public void bindTargetObjects(IEnumerable<GameObject> targetObjects)
{
_lastExtrudeSpace = sharedSettings.extrudeSpace;
_targetObjects = targetObjects;
fitToTargetObjects();
}
public void onTargetObjectsUpdated()
{
fitToTargetObjects();
}
public void onTargetObjectTransformsChanged()
{
fitToTargetObjects();
}
public void projectObjectsBasedOnProjectionMode(List<GameObject> gameObjects)
{
if (sharedSettings.projectionMode == ObjectExtrudeGizmoProjectionMode.Terrains)
{
// Note: Record transform because the original is also included and we need to
// be able to undo/redo its transform change.
UndoEx.recordGameObjectTransforms(gameObjects);
OBB obb = ObjectBounds.calcHierarchiesWorldOBB(gameObjects, _targetBoundsQConfig);
PluginScene.instance.terrainsOverlapBox(obb, _terrainOverlapFilter, TerrainObjectOverlapConfig.defaultConfig, _terrains);
ObjectProjection.projectHierarchiesOnTerrainsAsUnit(gameObjects, _terrains, terrainProjectionSettings);
}
}
protected override void doOnSceneGUI()
{
if (_lastExtrudeSpace != sharedSettings.extrudeSpace)
{
fitToTargetObjects();
_lastExtrudeSpace = sharedSettings.extrudeSpace;
}
if (_boxSize.magnitude == 0.0f) return;
Event e = Event.current;
if (e.type == EventType.Repaint)
{
if (_spawnOnRepaint)
{
spawn();
_spawnOnRepaint = false;
}
}
else
if (e.type == EventType.MouseDown)
{
_dragStartPosition = position;
if (e.button == (int)MouseButton.LeftMouse)
refreshSpawnAnchors();
}
else
if (e.type == EventType.MouseUp || e.type == EventType.MouseLeaveWindow)
{
_dragStartPosition = position;
if (e.button == (int)MouseButton.LeftMouse && extruding)
{
_hoveredSglAxisSlider = null;
_hoveredDblAxisSlider = null;
_spawnOnRepaint = true;
}
}
updateSglAxisSliders();
updateDblAxisSliders();
drawWireBox();
drawSglAxisSliders();
drawDblAxisSliders();
if (extruding)
{
updateSpawnGrid();
drawSpawnGrid();
}
drawUIHandles();
}
protected override void onDestroy()
{
ScriptableObjectEx.destroyImmediate(_terrainProjectionSettings);
}
private void fitToTargetObjects()
{
GameObjectEx.getParents(_targetObjects, _targetParents);
if (sharedSettings.extrudeSpace == ObjectExtrudeSpace.Global)
{
AABB worldAABB = ObjectBounds.calcHierarchiesWorldAABB(_targetParents, _targetBoundsQConfig);
setAABB(worldAABB);
}
else
{
OBB worldOBB = ObjectBounds.calcHierarchiesWorldOBB(_targetParents, _targetBoundsQConfig);
setOBB(worldOBB);
}
}
private void refreshSpawnAnchors()
{
_spawnAnchorMap.Clear();
foreach (var parent in _targetParents)
_spawnAnchorMap.Add(parent, parent.transform.position - _dragStartPosition);
}
[NonSerialized]
private List<GameObject> _overlappedObjectsBuffer = new List<GameObject>();
private void spawn()
{
if (sharedSettings.avoidOverlaps)
{
_overlapFilter.clearIgnoredObjects();
_overlapFilter.addIgnoredObjects(_targetObjects);
}
var sceneGrid = PluginScene.instance.grid;
_spawnedParents.Clear();
for (int cellX = 0; cellX < _grid.numCellsX; ++cellX)
{
for (int cellZ = 0; cellZ < _grid.numCellsZ; ++cellZ)
{
_verticalAxisObjectsBuffer.Clear();
// Note: Traverse the Y axis last in order to gather columns of spawned
// objects in a single buffer for terrain projection.
for (int cellY = 0; cellY < _grid.numCellsY; ++cellY)
{
Vector3 cellPosition = _grid.calcCellPosition(cellX, cellY, cellZ);
// Note: If this is the cell in which the target objects reside,
// add it to the buffer to allow the to be projected later.
if (sharedSettings.projectionMode != ObjectExtrudeGizmoProjectionMode.None &&
_targetObjectsCellCoords.matchCoords(cellX, cellY, cellZ)) _verticalAxisObjectsBuffer.AddRange(_targetParents);
if (isGridCellMasked(cellX, cellY, cellZ, cellPosition)) continue;
foreach (var targetParent in _targetParents)
{
var spawnedParent = UnityEditorCommands.duplicate(targetParent);
if (spawnedParent != null)
{
spawnedParent.transform.position = cellPosition + _spawnAnchorMap[targetParent];
OBB hierarchyWorldOBB = ObjectBounds.calcHierarchyWorldOBB(spawnedParent, _overlapBoundsQConfig);
if (sharedSettings.avoidOverlaps)
{
OBB overlapOBB = hierarchyWorldOBB;
if (overlapOBB.isValid)
{
overlapOBB.inflate(-1e-1f);
if (PluginScene.instance.overlapBox(overlapOBB, _overlapFilter, ObjectOverlapConfig.defaultConfig, _overlappedObjectsBuffer))
{
bool foundOverlap = false;
foreach (var overlapped in _overlappedObjectsBuffer)
{
if (overlapped == spawnedParent || overlapped.transform.IsChildOf(spawnedParent.transform)) continue;
if (overlapped.getMesh() != null)
{
if (spawnedParent.meshHierarchyIntersectsMeshTriangles(overlapped, -1e-1f))
{
foundOverlap = true;
break;
}
}
else
{
foundOverlap = true;
break;
}
}
if (foundOverlap)
GameObject.DestroyImmediate(spawnedParent);
}
}
}
if (spawnedParent != null)
{
_spawnedParents.Add(spawnedParent);
_verticalAxisObjectsBuffer.Add(spawnedParent);
}
}
}
}
if (_verticalAxisObjectsBuffer.Count != 0)
{
projectObjectsBasedOnProjectionMode(_verticalAxisObjectsBuffer);
if (verticalAxisExtrudeSpawn != null)
verticalAxisExtrudeSpawn(this, _verticalAxisObjectsBuffer);
}
}
}
if (_spawnedParents.Count != 0 && extrudeSpawn != null) extrudeSpawn(this, _spawnedParents);
_spawnedParents.Clear();
}
private void updateSglAxisSliders()
{
Vector3 right = boxRotation * Vector3.right;
Vector3 up = boxRotation * Vector3.up;
Vector3 look = boxRotation * Vector3.forward;
var slider = _sglAxisSliders[(int)SglAxisSlider.Id.Left];
slider.direction = -right;
slider.position = boxCenter + slider.direction * boxExtents.x;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.x > _minBoxSize;
slider = _sglAxisSliders[(int)SglAxisSlider.Id.Right];
slider.direction = right;
slider.position = boxCenter + slider.direction * boxExtents.x;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.x > _minBoxSize;
slider = _sglAxisSliders[(int)SglAxisSlider.Id.Top];
slider.direction = up;
slider.position = boxCenter + slider.direction * boxExtents.y;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.y > _minBoxSize;
slider = _sglAxisSliders[(int)SglAxisSlider.Id.Bottom];
slider.direction = -up;
slider.position = boxCenter + slider.direction * boxExtents.y;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.y > _minBoxSize;
slider = _sglAxisSliders[(int)SglAxisSlider.Id.Forward];
slider.direction = look;
slider.position = boxCenter + slider.direction * boxExtents.z;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.z > _minBoxSize;
slider = _sglAxisSliders[(int)SglAxisSlider.Id.Back];
slider.direction = -look;
slider.position = boxCenter + slider.direction * boxExtents.z;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.z > _minBoxSize;
}
private void updateDblAxisSliders()
{
Vector3 right = boxRotation * Vector3.right;
Vector3 up = boxRotation * Vector3.up;
Vector3 look = boxRotation * Vector3.forward;
var slider = _dblAxisSliders[(int)DblAxisSlider.Id.RightForward];
slider.direction = (right + look).normalized;
slider.position = boxCenter + right * boxExtents.x + look * boxExtents.z;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.x > _minBoxSize && boxSize.z > _minBoxSize;
slider = _dblAxisSliders[(int)DblAxisSlider.Id.RightBack];
slider.direction = (right - look).normalized;
slider.position = boxCenter + right * boxExtents.x - look * boxExtents.z;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.x > _minBoxSize && boxSize.z > _minBoxSize;
slider = _dblAxisSliders[(int)DblAxisSlider.Id.LeftBack];
slider.direction = (-right - look).normalized;
slider.position = boxCenter - right * boxExtents.x - look * boxExtents.z;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.x > _minBoxSize && boxSize.z > _minBoxSize;
slider = _dblAxisSliders[(int)DblAxisSlider.Id.LeftForward];
slider.direction = (-right + look).normalized;
slider.position = boxCenter - right * boxExtents.x + look * boxExtents.z;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.x > 0.0f && boxSize.z > 0.0f;
slider = _dblAxisSliders[(int)DblAxisSlider.Id.TopLeft];
slider.direction = (up - right).normalized;
slider.position = boxCenter + up * boxExtents.y - right * boxExtents.x;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.x > _minBoxSize && boxSize.y > _minBoxSize;
slider = _dblAxisSliders[(int)DblAxisSlider.Id.TopRight];
slider.direction = (up + right).normalized;
slider.position = boxCenter + up * boxExtents.y + right * boxExtents.x;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.x > _minBoxSize && boxSize.y > _minBoxSize;
slider = _dblAxisSliders[(int)DblAxisSlider.Id.BottomRight];
slider.direction = (-up + right).normalized;
slider.position = boxCenter - up * boxExtents.y + right * boxExtents.x;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.x > _minBoxSize && boxSize.y > _minBoxSize;
slider = _dblAxisSliders[(int)DblAxisSlider.Id.BottomLeft];
slider.direction = (-up - right).normalized;
slider.position = boxCenter - up * boxExtents.y - right * boxExtents.x;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.x > _minBoxSize && boxSize.y > _minBoxSize;
slider = _dblAxisSliders[(int)DblAxisSlider.Id.ForwardTop];
slider.direction = (up + look).normalized;
slider.position = boxCenter + up * boxExtents.y + look * boxExtents.z;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.y > _minBoxSize && boxSize.z > _minBoxSize;
slider = _dblAxisSliders[(int)DblAxisSlider.Id.ForwardBottom];
slider.direction = (-up + look).normalized;
slider.position = boxCenter - up * boxExtents.y + look * boxExtents.z;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.y > _minBoxSize && boxSize.z > _minBoxSize;
slider = _dblAxisSliders[(int)DblAxisSlider.Id.BackBottom];
slider.direction = (-up - look).normalized;
slider.position = boxCenter - up * boxExtents.y - look * boxExtents.z;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.y > _minBoxSize && boxSize.z > _minBoxSize;
slider = _dblAxisSliders[(int)DblAxisSlider.Id.BackTop];
slider.direction = (up - look).normalized;
slider.position = boxCenter + up * boxExtents.y - look * boxExtents.z;
slider.controlId = GUIUtility.GetControlID(FocusType.Passive);
slider.visible = boxSize.y > _minBoxSize && boxSize.z > _minBoxSize;
}
private void updateSpawnGrid()
{
_grid.origin = _dragStartPosition;
_grid.cellSize = _boxSize;
_grid.cellRotation = boxRotation;
_grid.right = boxRotation * Vector3.right;
_grid.up = boxRotation * Vector3.up;
_grid.look = boxRotation * Vector3.forward;
_grid.padding = sharedSettings.padding;
Vector3 toPosition = position - _dragStartPosition;
_grid.numCells = Vector3Int.one;
if (_boxSize[0] > 0.0f) _grid.numCellsX = 1 + Mathf.RoundToInt(toPosition.absDot(boxRotation * Vector3.right) / calcDragSize(0));
if (_boxSize[1] > 0.0f) _grid.numCellsY = 1 + Mathf.RoundToInt(toPosition.absDot(boxRotation * Vector3.up) / calcDragSize(1));
if (_boxSize[2] > 0.0f) _grid.numCellsZ = 1 + Mathf.RoundToInt(toPosition.absDot(boxRotation * Vector3.forward) / calcDragSize(2));
if (_hoveredSglAxisSlider != null)
{
if (_hoveredSglAxisSlider.isXAxis)
{
_grid.right = _hoveredSglAxisSlider.dragDirection;
_targetObjectsCellCoords = new Vector3Int(0, 0, 0);
}
else if (_hoveredSglAxisSlider.isYAxis)
{
_grid.up = _hoveredSglAxisSlider.dragDirection;
_targetObjectsCellCoords = new Vector3Int(0, 0, 0);
}
else if (_hoveredSglAxisSlider.isZAxis)
{
_grid.look = _hoveredSglAxisSlider.dragDirection;
_targetObjectsCellCoords = new Vector3Int(0, 0, 0);
}
}
else
if (_hoveredDblAxisSlider != null)
{
_targetObjectsCellCoords = Vector3Int.zero;
if (_hoveredDblAxisSlider.isXZAxis)
{
_grid.right = rotation * Vector3.right * _hoveredDblAxisSlider.dragSign0;
_grid.look = rotation * Vector3.forward * _hoveredDblAxisSlider.dragSign1;
_targetObjectsCellCoords.x = 0;
_targetObjectsCellCoords.z = 0;
}
else
if (_hoveredDblAxisSlider.isYXAxis)
{
_grid.up = rotation * Vector3.up * _hoveredDblAxisSlider.dragSign0;
_grid.right = rotation * Vector3.right * _hoveredDblAxisSlider.dragSign1;
_targetObjectsCellCoords.y = 0;
_targetObjectsCellCoords.x = 0;
}
else
if (_hoveredDblAxisSlider.isZYAxis)
{
_grid.look = rotation * Vector3.forward * _hoveredDblAxisSlider.dragSign0;
_grid.up = rotation * Vector3.up * _hoveredDblAxisSlider.dragSign1;
_targetObjectsCellCoords.z = 0;
_targetObjectsCellCoords.y = 0;
}
}
}
private void drawSpawnGrid()
{
_grid.cellFillColor = GizmoPrefs.instance.extrudeCellFillColor;
_grid.cellWireColor = GizmoPrefs.instance.extrudeCellWireColor;
_grid.draw();
}
private void drawWireBox()
{
HandlesEx.saveMatrix();
HandlesEx.saveColor();
Handles.matrix = Matrix4x4.TRS(position, rotation, _boxSize);
Handles.color = GizmoPrefs.instance.extrudeWireColor;
//Handles.DrawWireCube(Vector3.zero, Vector3.one);
HandlesEx.drawUnitWireCube();
HandlesEx.restoreColor();
HandlesEx.restoreMatrix();
}
private void drawSglAxisSliders()
{
HandlesEx.saveColor();
HandlesEx.saveMatrix();
Vector3 padding = sharedSettings.padding;
_hoveredSglAxisSlider = null;
foreach (var slider in _sglAxisSliders)
{
if (!slider.visible) continue;
Color sliderColor = GizmoPrefs.instance.extrudeXAxisColor;
if (slider.isYAxis) sliderColor = GizmoPrefs.instance.extrudeYAxisColor;
else if (slider.isZAxis) sliderColor = GizmoPrefs.instance.extrudeZAxisColor;
Handles.color = sliderColor;
EditorGUI.BeginChangeCheck();
Vector3 newPos = Handles.Slider(slider.controlId, slider.position, slider.direction, getSglAxisHandleSize(), Handles.ConeHandleCap, 0.0f);
if (EditorGUI.EndChangeCheck())
{
slider.dragSign = Mathf.Sign(Vector3.Dot(slider.direction, (newPos - _dragStartPosition)));
float t;
Ray ray = PluginCamera.camera.getCursorRay();
Plane dragPlane = PlaneEx.createPlaneWithMostAlignedNormal(slider.axis, rotation, PluginCamera.camera.transform.forward, slider.position);
if (dragPlane.Raycast(ray, out t))
{
Vector3 intersectPt = ray.GetPoint(t);
Vector3 direction = (intersectPt - position);
Vector3 moveVector = Vector3.zero;
float dot = Vector3.Dot(direction, slider.direction);
float dragSize = calcDragSize(slider.axis);
if (Mathf.Abs(dot) >= dragSize)
{
int numCells = Mathf.RoundToInt(Mathf.Abs(dot) / dragSize);
moveVector += slider.direction * dragSize * numCells * Mathf.Sign(dot);
}
if (moveVector.magnitude > 0.0f)
{
UndoEx.record(this);
position += moveVector;
//moveTargets(moveVector);
}
}
}
}
HandlesEx.restoreMatrix();
HandlesEx.restoreColor();
foreach (var slider in _sglAxisSliders)
{
if (slider.controlId == GUIUtility.hotControl)
{
_hoveredSglAxisSlider = slider;
break;
}
}
}
private void drawDblAxisSliders()
{
HandlesEx.saveColor();
_hoveredDblAxisSlider = null;
foreach (var slider in _dblAxisSliders)
{
if (!slider.visible) continue;
if (slider.isZYAxis) Handles.color = GizmoPrefs.instance.extrudeXAxisColor;
else if (slider.isYXAxis) Handles.color = GizmoPrefs.instance.extrudeZAxisColor;
else Handles.color = GizmoPrefs.instance.extrudeYAxisColor;
EditorGUI.BeginChangeCheck();
Handles.Slider(slider.controlId, slider.position, slider.direction, getDblAxisHandleSize(), Handles.DotHandleCap, 0.0f);
if (EditorGUI.EndChangeCheck())
{
Vector3 axis0 = Vector3Ex.createAxis(slider.axis0, rotation);
Vector3 axis1 = Vector3Ex.createAxis(slider.axis1, rotation);
slider.dragSign0 = Mathf.Sign(Vector3.Dot((position - _dragStartPosition), axis0));
slider.dragSign1 = Mathf.Sign(Vector3.Dot((position - _dragStartPosition), axis1));
float t;
Ray ray = PluginCamera.camera.getCursorRay();
Plane dragPlane = new Plane(Vector3.Cross(axis0, axis1).normalized, _dragStartPosition);
if (dragPlane.Raycast(ray, out t))
{
Vector3 intersectPt = ray.GetPoint(t);
Vector3 direction = (intersectPt - position);
Vector3 moveVector = Vector3.zero;
float dot0 = Vector3.Dot(direction, axis0);
float dragSize0 = calcDragSize(slider.axis0);
if (Mathf.Abs(dot0) >= dragSize0)
{
int numCells = Mathf.RoundToInt(Mathf.Abs(dot0) / dragSize0);
moveVector += axis0 * dragSize0 * numCells * Mathf.Sign(dot0);
}
float dot1 = Vector3.Dot(direction, axis1);
float dragSize1 = calcDragSize(slider.axis1);
if (Mathf.Abs(dot1) >= _boxSize[slider.axis1])
{
int numCells = Mathf.RoundToInt(Mathf.Abs(dot1) / dragSize1);
moveVector += axis1 * dragSize1 * numCells * Mathf.Sign(dot1);
}
if (moveVector.magnitude > 0.0f)
{
UndoEx.record(this);
position += moveVector;
//moveTargets(moveVector);
}
}
}
}
HandlesEx.restoreColor();
foreach (var slider in _dblAxisSliders)
{
if (slider.controlId == GUIUtility.hotControl)
{
_hoveredDblAxisSlider = slider;
break;
}
}
}
private float calcDragSize(int axis)
{
return _boxSize[axis] + sharedSettings.padding[axis];
}
private void drawUIHandles()
{
if (_grid.hasCells && extruding)
{
if (GizmoPrefs.instance.extrudeShowInfoText)
{
Handles.BeginGUI();
Vector3 labelPos = _grid.calcCellPosition(0, 0, 0);
labelPos -= _grid.right * _grid.cellSize.x * 0.5f;
labelPos -= _grid.up * _grid.cellSize.y * 0.5f;
labelPos -= _grid.look * _grid.cellSize.z * 0.5f;
Handles.Label(labelPos, "X: " + _grid.numCellsX + ", Y:" + _grid.numCellsY + ", Z: " + _grid.numCellsZ, GUIStyleDb.instance.sceneViewInfoLabel);
Handles.EndGUI();
}
}
}
private float getSglAxisHandleSize()
{
return HandleUtility.GetHandleSize(position) * GizmoPrefs.instance.extrudeSglHandleSize;
}
private float getDblAxisHandleSize()
{
return HandleUtility.GetHandleSize(position) * GizmoPrefs.instance.extrudeDblAxisSize;
}
private void setAABB(AABB aabb)
{
if (!aabb.isValid)
{
_boxSize = Vector3.zero;
return;
}
_boxSize = aabb.size.abs();
rotation = Quaternion.identity;
position = aabb.center;
}
private void setOBB(OBB obb)
{
if (!obb.isValid)
{
_boxSize = Vector3.zero;
return;
}
_boxSize = obb.size.abs();
rotation = obb.rotation;
position = obb.center;
}
private void moveTargets(Vector3 moveVector)
{
UndoEx.recordGameObjectTransforms(_targetParents);
foreach (var parent in _targetParents)
parent.transform.position += moveVector;
}
private bool isGridCellMasked(int cellX, int cellY, int cellZ, Vector3 cellPosition)
{
// Note: Ignore the cell that encapsulates the target objects.
if (_targetObjectsCellCoords.matchCoords(cellX, cellY, cellZ)) return true;
return false;
// Note: This was used back when pattern step was used instead of padding.
/*Vector3Int patternStep = sharedSettings.patternStep;
if (patternStep.x != 0)
{
int groupIndex = (int)(cellX / (float)patternStep.x);
if ((groupIndex % 2) != 0) return true;
}
if (patternStep.y != 0)
{
int groupIndex = (int)(cellY / (float)patternStep.y);
if ((groupIndex % 2) != 0) return true;
}
if (patternStep.z != 0)
{
int groupIndex = (int)(cellZ / (float)patternStep.z);
if ((groupIndex % 2) != 0) return true;
}
return false;*/
}
}
}
#endif