You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
306 lines
8.6 KiB
C#
306 lines
8.6 KiB
C#
/******************************************************************************/
|
|
/*
|
|
Project - MudBun
|
|
Publisher - Long Bunny Labs
|
|
http://LongBunnyLabs.com
|
|
Author - Ming-Lun "Allen" Chou
|
|
http://AllenChou.net
|
|
*/
|
|
/******************************************************************************/
|
|
|
|
using System.Collections.Generic;
|
|
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
|
|
using Unity.Collections;
|
|
using UnityEngine;
|
|
|
|
namespace MudBun
|
|
{
|
|
/// <summary>
|
|
/// The base class for all brushes. Users should extend one of the MudSolid, MudDistortion, or MudModifier classes to create custom brushes.
|
|
/// </summary>
|
|
[ExecuteInEditMode]
|
|
public abstract class MudBrushBase : MonoBehaviour
|
|
{
|
|
internal MudRendererBase m_renderer;
|
|
internal int m_iSdfBrush;
|
|
internal bool m_dirty = true;
|
|
|
|
#if UNITY_EDITOR
|
|
[HideInInspector] public bool Hidden = false;
|
|
#else
|
|
public bool Hidden => false;
|
|
#endif
|
|
|
|
public MudRendererBase Renderer => m_renderer;
|
|
|
|
public void MarkDirty() { m_dirty = true; }
|
|
|
|
/// <summary>
|
|
/// The actual bounds in renderer space used for spatial optimization. Normally this would be the same as BoundsRs, but for special situations like solid brushes with symmetry turned on, this would be a modified version of BoundsRs.
|
|
/// </summary>
|
|
public virtual Aabb BoundsRs
|
|
{
|
|
get
|
|
{
|
|
Aabb bounds = RawBoundsRs;
|
|
|
|
Transform t = transform.parent;
|
|
while (t != null)
|
|
{
|
|
MudBrushGroup group = t.GetComponent<MudBrushGroup>();
|
|
if (group != null)
|
|
{
|
|
bounds.Expand(group.Blend);
|
|
}
|
|
t = t.parent;
|
|
}
|
|
|
|
return bounds;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// The raw AABB bounds in renderer space. This should be always encompass the brush's maximum range of effect. Otherwise, parts of the brush's effect could be missing due to the renderer's spatial optimization.
|
|
/// </summary>
|
|
public virtual Aabb RawBoundsRs => Aabb.Empty;
|
|
public virtual float BoundsRsPadding => 0.0f;
|
|
public virtual bool IsSuccessorModifier => false;
|
|
public virtual bool ShouldUseAccumulatedBounds => false;
|
|
|
|
internal bool m_preChildrenFlag = false;
|
|
public virtual bool IsBrushGroup => false;
|
|
|
|
internal virtual bool UsesMaterial => false;
|
|
internal virtual int MaterialHash => 0;
|
|
|
|
internal int m_iProxy = AabbTree<MudBrushBase>.Null;
|
|
public virtual void UpdateProxies(AabbTree<MudBrushBase> tree, Aabb opBounds)
|
|
{
|
|
if (m_iProxy == AabbTree<MudBrushBase>.Null)
|
|
m_iProxy = tree.CreateProxy(opBounds, this);
|
|
|
|
tree.UpdateProxy(m_iProxy, opBounds, m_iSdfBrush);
|
|
}
|
|
|
|
public virtual void DestroyProxies(AabbTree<MudBrushBase> tree)
|
|
{
|
|
tree.DestroyProxy(m_iProxy);
|
|
m_iProxy = AabbTree<MudBrushBase>.Null;
|
|
}
|
|
|
|
public Aabb BoundaryShapeBounds(SdfBrush.BoundaryShapeEnum boundaryShape, float radius)
|
|
{
|
|
Vector3 size = transform.localScale;
|
|
Aabb bounds = Aabb.Empty;
|
|
switch (boundaryShape)
|
|
{
|
|
case SdfBrush.BoundaryShapeEnum.Box:
|
|
{
|
|
Vector3 r = 0.5f * size;
|
|
bounds = new Aabb(-r, r);
|
|
bounds.Rotate(RotationRs(transform.rotation));
|
|
break;
|
|
}
|
|
|
|
case SdfBrush.BoundaryShapeEnum.Sphere:
|
|
{
|
|
Vector3 r = radius * size;
|
|
bounds = new Aabb(-r, r);
|
|
bounds.Rotate(RotationRs(transform.rotation));
|
|
break;
|
|
}
|
|
|
|
case SdfBrush.BoundaryShapeEnum.Cylinder:
|
|
{
|
|
Vector3 r = new Vector3(radius + Mathf.Max(0.0f, size.x - 1.0f), 0.5f * size.y, radius + Mathf.Max(0.0f, size.z - 1.0f));
|
|
bounds = new Aabb(-r, r);
|
|
bounds.Rotate(RotationRs(transform.rotation));
|
|
break;
|
|
}
|
|
|
|
case SdfBrush.BoundaryShapeEnum.Torus:
|
|
{
|
|
Vector3 r = new Vector3(0.5f * size.x, 0.0f, 0.5f * size.z);
|
|
bounds = new Aabb(-r, r);
|
|
bounds.Rotate(RotationRs(transform.rotation));
|
|
Vector3 round = radius * Vector3.one;
|
|
bounds.Min -= round;
|
|
bounds.Max += round;
|
|
break;
|
|
}
|
|
|
|
case SdfBrush.BoundaryShapeEnum.SolidAngle:
|
|
{
|
|
Vector3 r = radius * VectorUtil.Abs(transform.localScale);
|
|
bounds = new Aabb(-r, r);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bounds;
|
|
}
|
|
|
|
protected virtual void ScanRenderer() { }
|
|
|
|
public virtual void OnEnable()
|
|
{
|
|
m_renderer = null;
|
|
m_iProxy = AabbTree<MudBrushBase>.Null;
|
|
m_iSdfBrush = -1;
|
|
MarkDirty();
|
|
|
|
ScanRenderer();
|
|
}
|
|
|
|
public virtual void OnDisable()
|
|
{
|
|
if (m_renderer != null)
|
|
m_renderer.OnBrushDisabled(this);
|
|
|
|
#if UNITY_EDITOR
|
|
SelectionManager.NotifyBrushDisabled(this);
|
|
#endif
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
SanitizeParameters();
|
|
MarkDirty();
|
|
}
|
|
|
|
public virtual void SanitizeParameters() { }
|
|
|
|
// Ws: world space
|
|
// Rs: renderer space
|
|
// Bs: brush space
|
|
|
|
public Vector3 PointRs(Vector3 posWs)
|
|
{
|
|
return
|
|
m_renderer != null
|
|
? m_renderer.transform.InverseTransformPoint(posWs)
|
|
: posWs;
|
|
}
|
|
|
|
public Vector3 VectorRs(Vector3 vecWs)
|
|
{
|
|
return
|
|
m_renderer != null
|
|
? m_renderer.transform.InverseTransformVector(vecWs)
|
|
: vecWs;
|
|
}
|
|
|
|
public Quaternion RotationRs(Quaternion rotWs)
|
|
{
|
|
return
|
|
m_renderer != null
|
|
? Quaternion.Inverse(m_renderer.transform.rotation) * rotWs
|
|
: rotWs;
|
|
}
|
|
|
|
public Vector3 PointBs(Vector3 posWs) => transform.InverseTransformPoint(posWs);
|
|
public Vector3 VectorBs(Vector3 vecWs) => transform.InverseTransformVector(vecWs);
|
|
public Quaternion RotationBs(Quaternion rotWs) => Quaternion.Inverse(transform.rotation) * rotWs;
|
|
|
|
public virtual bool CountAsBone => false;
|
|
|
|
public virtual int FillComputeData(NativeArray<SdfBrush> aBrush, int iStart, List<Transform> aBone) { return 0; }
|
|
public virtual void FillBrushData(ref SdfBrush brush, int iBrush)
|
|
{
|
|
brush.Proxy = m_iProxy;
|
|
|
|
brush.Position = PointRs(transform.position);
|
|
brush.Rotation = RotationRs(transform.rotation);
|
|
brush.Size = transform.localScale;
|
|
|
|
brush.Flags.AssignBit((int) SdfBrush.FlagBit.Hidden, Hidden);
|
|
}
|
|
|
|
public virtual int FillComputeDataPostChildren(NativeArray<SdfBrush> aBrush, int iStart) { return 0; }
|
|
public virtual void FillBrushDataPostChildren(ref SdfBrush brush, int iBrush) { }
|
|
|
|
public virtual void FillBrushMaterialData(ref SdfBrushMaterial mat) { }
|
|
|
|
public virtual void ValidateMaterial() { }
|
|
|
|
private struct Locator
|
|
{
|
|
public Vector3 Position;
|
|
public Quaternion Rotation;
|
|
}
|
|
|
|
public IList<Transform> GetFlipXTransforms()
|
|
{
|
|
var aTransform = new List<Transform>();
|
|
CollectChildrenRecursive(transform, aTransform);
|
|
return aTransform;
|
|
}
|
|
|
|
public void FlipX()
|
|
{
|
|
var aTransform = new List<Transform>();
|
|
CollectChildrenRecursive(transform, aTransform);
|
|
var aMirroredLocator = new List<Locator>(aTransform.Count);
|
|
|
|
for (int i = 0; i < aTransform.Count; ++i)
|
|
{
|
|
var t = aTransform[i];
|
|
Locator loc = new Locator() { Position = t.position, Rotation = t.rotation };
|
|
loc.Position.x = -loc.Position.x;
|
|
loc.Rotation.y = -loc.Rotation.y;
|
|
loc.Rotation.z = -loc.Rotation.z;
|
|
aMirroredLocator.Add(loc);
|
|
}
|
|
|
|
for (int i = 0; i < aTransform.Count; ++i)
|
|
{
|
|
var t = aTransform[i];
|
|
var loc = aMirroredLocator[i];
|
|
t.position = loc.Position;
|
|
t.rotation = loc.Rotation;
|
|
}
|
|
}
|
|
|
|
private void CollectChildrenRecursive(Transform t, List<Transform> aTransform)
|
|
{
|
|
aTransform.Add(t);
|
|
for (int i = 0; i < t.childCount; ++i)
|
|
CollectChildrenRecursive(t.GetChild(i), aTransform);
|
|
}
|
|
|
|
public float GetFloatHash() => Mathf.Abs(Codec.Hash(GetHashCode()) % 0xFFFF) / ((float) 0xFFFF);
|
|
|
|
internal virtual bool IsSelected()
|
|
{
|
|
#if UNITY_EDITOR
|
|
bool selected = Selection.Contains(gameObject);
|
|
#else
|
|
bool selected = false;
|
|
#endif
|
|
return selected;
|
|
}
|
|
|
|
protected virtual void OnDrawGizmos()
|
|
{
|
|
if (Renderer == null)
|
|
return;
|
|
|
|
if (Renderer.ClickSelection != MudRendererBase.ClickSelectionEnum.Gizmos)
|
|
return;
|
|
|
|
Gizmos.matrix = Renderer.transform.localToWorldMatrix;
|
|
DrawSelectionGizmosRs();
|
|
Gizmos.matrix = Matrix4x4.identity;
|
|
}
|
|
|
|
public virtual void DrawGizmosRs() { }
|
|
public virtual void DrawSelectionGizmosRs() { }
|
|
public virtual void DrawOutlineGizmosRs() { }
|
|
}
|
|
}
|
|
|
|
|