using System;
using UnityEngine;
using UnityEngine.Splines;
using Object = UnityEngine.Object;
namespace UnityEditor.Splines
{
///
/// Creates a cylinder mesh along a spline.
///
/// The type of ISpline.
public class SplineMeshHandle : IDisposable where T : ISpline
{
class SplineMeshDrawingScope : IDisposable
{
Material m_Material;
int m_HandleZTestId;
int m_BlendSrcModeId;
int m_BlendDstModeId;
float m_PreviousZTest;
int m_PreviousBlendSrcMode;
int m_PreviousBlendDstMode;
public SplineMeshDrawingScope(Material material, Color color)
{
Shader.SetGlobalColor("_HandleColor", color);
Shader.SetGlobalFloat("_HandleSize", 1f);
Shader.SetGlobalMatrix("_ObjectToWorld", Handles.matrix);
if (material == null)
{
m_Material = HandleUtility.handleMaterial;
m_HandleZTestId = Shader.PropertyToID("_HandleZTest");
m_BlendSrcModeId = Shader.PropertyToID("_BlendSrcMode");
m_BlendDstModeId = Shader.PropertyToID("_BlendDstMode");
m_PreviousZTest = m_Material.GetFloat(m_HandleZTestId);
m_PreviousBlendSrcMode = m_Material.GetInt(m_BlendSrcModeId);
m_PreviousBlendDstMode = m_Material.GetInt(m_BlendDstModeId);
m_Material.SetFloat(m_HandleZTestId, (float)Handles.zTest);
m_Material.SetInt(m_BlendSrcModeId, (int)UnityEngine.Rendering.BlendMode.One);
m_Material.SetInt(m_BlendDstModeId, (int)UnityEngine.Rendering.BlendMode.One);
m_Material.SetPass(0);
}
else
material.SetPass(0);
}
public void Dispose()
{
if (m_Material != null)
{
m_Material.SetFloat(m_HandleZTestId, m_PreviousZTest);
m_Material.SetInt(m_BlendSrcModeId, m_PreviousBlendSrcMode);
m_Material.SetInt(m_BlendDstModeId, m_PreviousBlendDstMode);
}
}
}
Mesh m_Mesh;
Material m_Material;
///
/// Creates a new mesh handle. This class implements IDisposable to clean up allocated mesh resources. Call
/// when you are finished with the instance.
///
public SplineMeshHandle()
{
m_Mesh = new Mesh()
{
hideFlags = HideFlags.HideAndDontSave
};
m_Material = null;
}
///
/// Create a new mesh handle. This class implements IDisposable to clean up allocated mesh resources. Call
/// when you are finished with the instance.
///
/// The material to render the cylinder mesh with.
public SplineMeshHandle(Material material) : base()
{
m_Material = material;
}
///
/// The material to render this mesh with. If null, a default material is used.
///
public Material material
{
get => m_Material;
set => m_Material = value;
}
///
/// Draws a 3D mesh from a spline.
///
/// The target spline.
/// The width to use for the spline mesh.
/// The color to use for the spline mesh in normal mode.
/// The resolution to use for the mesh, defines the number of segments per unit
/// with default value of .
public void Do(T spline, float size, Color color, int resolution = SplineUtility.DrawResolutionDefault)
{
if(Event.current.type != EventType.Repaint)
return;
Do(-1, spline, size, color, resolution);
}
///
/// Draws a 3D mesh handle from a spline.
///
/// The spline mesh controlID.
/// The target spline.
/// The width to use for the spline mesh.
/// The color to use for the spline mesh in normal mode.
/// The resolution to use for the mesh, defines the number of segments per unit
/// with default value of .
public void Do(int controlID, T spline, float size, Color color, int resolution = SplineUtility.DrawResolutionDefault)
{
using (new Handles.DrawingScope(color))
Do(controlID, spline, size, resolution);
}
///
/// Draws a 3D mesh from a spline.
///
/// The target spline.
/// The width to use for the spline mesh.
/// The resolution to use for the mesh, defines the number of segments per unit
/// with default value of .
public void Do(T spline, float size, int resolution = SplineUtility.DrawResolutionDefault)
{
if (Event.current.type != EventType.Repaint)
return;
Do(-1, spline, size, resolution);
}
///
/// Draws a 3D mesh handle from a spline.
///
/// The spline mesh controlID.
/// The target spline.
/// The width to use for the spline mesh.
/// The resolution to use for the mesh, defines the number of segments per unit
/// with default value of .
public void Do(int controlID, T spline, float size, int resolution = SplineUtility.DrawResolutionDefault)
{
var evt = Event.current;
switch (evt.type)
{
case EventType.MouseMove:
var ray = HandleUtility.GUIPointToWorldRay(evt.mousePosition);
HandleUtility.AddControl(controlID, SplineUtility.GetNearestPoint(spline, ray, out _, out _));
break;
case EventType.Repaint:
var segments = SplineUtility.GetSubdivisionCount(spline.GetLength(), resolution);
SplineMesh.Extrude(spline, m_Mesh, size, 8, segments, !spline.Closed);
var color = GUIUtility.hotControl == controlID
? Handles.selectedColor
: HandleUtility.nearestControl == controlID
? Handles.preselectionColor
: Handles.color;
using (new SplineMeshDrawingScope(m_Material, color))
Graphics.DrawMeshNow(m_Mesh, Handles.matrix);
break;
}
}
///
/// Destroys the 3D mesh.
///
public void Dispose() => Object.DestroyImmediate(m_Mesh);
}
}