BITFALL/Assets/GSpawn - Level Designer/Scripts/Objects/Transform Sessions/ObjectVertexSnapSession.cs

228 lines
11 KiB
C#

#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
namespace GSpawn
{
public class ObjectVertexSnapSession : ObjectTransformSession
{
private class SnapPivot
{
public enum Owner
{
Mesh,
Other
}
public bool isAvailable;
public Vector3 position;
public Vector3 normal;
public Vector3[] triangleVerts = new Vector3[3];
public Owner owner = Owner.Other;
}
private SnapPivot _snapPivot = new SnapPivot();
private SceneRaycastFilter _pickSnapPivotRaycastFilter = new SceneRaycastFilter() { objectTypes = GameObjectType.Mesh | GameObjectType.Sprite, usePrimeFocusObjects = true };
private SceneRaycastFilter _pickSnapDestRaycastFilter = new SceneRaycastFilter();
private List<GameObject> _gameObjectBuffer = new List<GameObject>();
private List<ObjectRayHit> _objectRayHitBuffer = new List<ObjectRayHit>();
private List<Vector3> _vector3Buffer = new List<Vector3>();
private Vector3[] _triangleVertBuffer = new Vector3[3];
private Vector3[] _quadVertBuffer = new Vector3[5];
public ObjectVertexSnapSettings sharedSettings { get; set; }
public override string sessionName { get { return "Vertex Snap"; } }
public override ObjectTransformSessionType sessionType { get { return ObjectTransformSessionType.VertexSnap; } }
protected override void update()
{
if (Mouse.instance.isButtonDown(0)) snap();
else pickSnapVertex();
}
protected override bool onCanBegin()
{
return sharedSettings != null;
}
protected override bool onBegin()
{
_snapPivot.isAvailable = false;
_pickSnapPivotRaycastFilter.setPrimeFocusObjects(_allTargetObjects);
return true;
}
protected override void onEnd()
{
_snapPivot.isAvailable = false;
}
protected override void draw()
{
HandlesEx.saveColor();
var sessionPrefs = ObjectTransformSessionPrefs.instance;
if (_snapPivot.isAvailable)
{
if (_snapPivot.owner == SnapPivot.Owner.Mesh)
{
Handles.color = sessionPrefs.vertSnapTriangleWireColor;
Handles.DrawLine(_snapPivot.triangleVerts[0], _snapPivot.triangleVerts[1]);
Handles.DrawLine(_snapPivot.triangleVerts[1], _snapPivot.triangleVerts[2]);
Handles.DrawLine(_snapPivot.triangleVerts[2], _snapPivot.triangleVerts[0]);
}
Handles.color = sessionPrefs.vertSnapTickColor;
Handles.DotHandleCap(0, _snapPivot.position, Quaternion.identity, HandleUtility.GetHandleSize(_snapPivot.position) * sessionPrefs.vertSnapTickSize, EventType.Repaint);
}
HandlesEx.restoreColor();
}
private void pickSnapVertex()
{
_snapPivot.isAvailable = false;
PluginScene.instance.raycastAll(PluginCamera.camera.getCursorRay(), _pickSnapPivotRaycastFilter, ObjectRaycastConfig.defaultConfig, true, _objectRayHitBuffer);
if (_objectRayHitBuffer.Count != 0)
{
var closestHit = _objectRayHitBuffer[0];
GameObjectType objectType = GameObjectDataDb.instance.getGameObjectType(closestHit.hitObject);
if (objectType == GameObjectType.Mesh)
{
PluginMesh pluginMesh = PluginMeshDb.instance.getPluginMesh(closestHit.hitObject.getMesh());
if (pluginMesh != null)
{
pluginMesh.getTriangleVerts(closestHit.meshRayHit.triangleIndex, _snapPivot.triangleVerts, closestHit.hitObject.transform);
int closestVert = Vector3Ex.findIndexOfPointClosestToPoint(_snapPivot.triangleVerts, closestHit.hitPoint);
if (closestVert >= 0)
{
_snapPivot.isAvailable = true;
_snapPivot.position = _snapPivot.triangleVerts[closestVert];
_snapPivot.normal = closestHit.hitNormal;
_snapPivot.owner = SnapPivot.Owner.Mesh;
}
}
}
if (objectType == GameObjectType.Sprite)
{
OBB worldOBB = ObjectBounds.calcSpriteWorldOBB(closestHit.hitObject);
if (worldOBB.isValid)
{
worldOBB.calcCenterAndCorners(_vector3Buffer);
int closestCorner = Vector3Ex.findIndexOfPointClosestToPoint(_vector3Buffer, closestHit.hitPoint);
if (closestCorner >= 0)
{
_snapPivot.isAvailable = true;
_snapPivot.position = _vector3Buffer[closestCorner];
_snapPivot.normal = closestHit.hitNormal;
_snapPivot.owner = SnapPivot.Owner.Other;
}
}
}
}
}
private void snap()
{
// Note: We need to check if the mouse has moved. It seems that if the
// mouse stays in the same position, due to (maybe) floating point
// rounding errors, the objects can snap to one plane and the
// vertex to another.
if (!_snapPivot.isAvailable || !Mouse.instance.hasMoved) return;
_pickSnapDestRaycastFilter.setIgnoredObjects(_targetObjects);
_pickSnapDestRaycastFilter.layerMask = sharedSettings.destinationLayers;
_pickSnapDestRaycastFilter.raycastGrid = sharedSettings.allowsGridDestination;
_pickSnapDestRaycastFilter.raycastObjects = sharedSettings.allowsObjectDestination;
_pickSnapDestRaycastFilter.objectTypes = GameObjectType.None;
if (sharedSettings.allowsObjectDestination)
{
if (sharedSettings.allowsMeshDestination) _pickSnapDestRaycastFilter.objectTypes |= GameObjectType.Mesh;
if (sharedSettings.allowsSpriteDestination) _pickSnapDestRaycastFilter.objectTypes |= GameObjectType.Sprite;
if (sharedSettings.allowsTerrainDestination) _pickSnapDestRaycastFilter.objectTypes |= GameObjectType.Terrain;
}
var sceneRayHit = PluginScene.instance.raycastClosest(PluginCamera.camera.getCursorRay(), _pickSnapDestRaycastFilter, ObjectRaycastConfig.defaultConfig);
if (sceneRayHit.anyHit)
{
if (sceneRayHit.wasGridHit && !sceneRayHit.wasObjectHit) snapToGrid(sceneRayHit.gridHit);
else
if (sceneRayHit.wasObjectHit && !sceneRayHit.wasGridHit)
{
GameObjectType objectType = GameObjectDataDb.instance.getGameObjectType(sceneRayHit.objectHit.hitObject);
if (objectType == GameObjectType.Mesh) snapToMeshObject(sceneRayHit.objectHit);
else if (objectType == GameObjectType.Terrain) snapToTerrainObject(sceneRayHit.objectHit);
else if (objectType == GameObjectType.Sprite) snapToSpriteObject(sceneRayHit.objectHit);
}
else
if (sceneRayHit.wasGridHit && sceneRayHit.wasObjectHit)
{
GameObjectType objectType = GameObjectDataDb.instance.getGameObjectType(sceneRayHit.objectHit.hitObject);
if (sceneRayHit.gridHit.hitEnter < sceneRayHit.objectHit.hitEnter &&
Mathf.Abs(sceneRayHit.gridHit.hitEnter - sceneRayHit.objectHit.hitEnter) > 1e-4f) snapToGrid(sceneRayHit.gridHit);
else if (objectType == GameObjectType.Mesh) snapToMeshObject(sceneRayHit.objectHit);
else if (objectType == GameObjectType.Terrain) snapToTerrainObject(sceneRayHit.objectHit);
else if (objectType == GameObjectType.Sprite) snapToSpriteObject(sceneRayHit.objectHit);
}
}
}
private void snapToGrid(GridRayHit gridRayHit)
{
gridRayHit.hitGrid.calcCellCenterAndCorners(gridRayHit.hitCell, true, _vector3Buffer);
var closestPt = Vector3Ex.findIndexOfPointClosestToPoint(_vector3Buffer, gridRayHit.hitPoint);
if (closestPt >= 0) applySnapVector(_vector3Buffer[closestPt] - _snapPivot.position);
}
private void snapToMeshObject(ObjectRayHit objectHit)
{
var pluginMesh = PluginMeshDb.instance.getPluginMesh(objectHit.hitObject.getMesh());
if (pluginMesh != null)
{
pluginMesh.getTriangleVerts(objectHit.meshRayHit.triangleIndex, _triangleVertBuffer, objectHit.hitObject.transform);
var closestPt = Vector3Ex.findIndexOfPointClosestToPoint(_triangleVertBuffer, objectHit.hitPoint);
if (closestPt >= 0) applySnapVector(_triangleVertBuffer[closestPt] - _snapPivot.position);
}
}
private void snapToTerrainObject(ObjectRayHit objectHit)
{
Terrain terrain = objectHit.hitObject.getTerrain();
terrain.calcQuadCorners(objectHit.hitPoint, _quadVertBuffer);
var closestPt = Vector3Ex.findIndexOfPointClosestToPoint(_quadVertBuffer, objectHit.hitPoint);
if (closestPt >= 0) applySnapVector(_quadVertBuffer[closestPt] - _snapPivot.position);
}
private void snapToSpriteObject(ObjectRayHit objectHit)
{
var spriteOBB = ObjectBounds.calcSpriteWorldOBB(objectHit.hitObject);
if (spriteOBB.isValid)
{
spriteOBB.calcCenterAndCorners(_vector3Buffer);
var closestPt = Vector3Ex.findIndexOfPointClosestToPoint(_vector3Buffer, objectHit.hitPoint);
if (closestPt >= 0) applySnapVector(_vector3Buffer[closestPt] - _snapPivot.position);
}
}
private void applySnapVector(Vector3 snapVector)
{
GameObjectEx.getParents(_targetObjects, _gameObjectBuffer);
UndoEx.recordGameObjectTransforms(_gameObjectBuffer);
foreach (var parent in _gameObjectBuffer)
parent.transform.position += snapVector;
ObjectEvents.onObjectsTransformed();
_snapPivot.position += snapVector;
if (_snapPivot.owner == SnapPivot.Owner.Mesh)
{
_snapPivot.triangleVerts[0] += snapVector;
_snapPivot.triangleVerts[1] += snapVector;
_snapPivot.triangleVerts[2] += snapVector;
}
}
}
}
#endif