Unity-DebugX/Runtime/Gizmos/DebugX.base.cs
2025-02-24 13:16:30 +08:00

601 lines
26 KiB
C#

//#undef DEBUG
using DCFApixels.DebugXCore;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Rendering;
using DCFApixels.DebugXCore.Internal;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace DCFApixels
{
using IN = System.Runtime.CompilerServices.MethodImplAttribute;
public static unsafe partial class DebugX
{
public readonly partial struct DrawHandler
{
#region Lambda //TODO
//[IN(LINE)]
//public DrawHandler Lambda(Action<(Color color, float duration)> drawCallback)
//{
// return Gizmo(new LambdaGizmo(drawCallback));
//}
//private readonly struct LambdaGizmo : IGizmo<LambdaGizmo>
//{
// public readonly Action<(Color color, float duration)> Action;
// [IN(LINE)] public LambdaGizmo(Action<(Color color, float duration)> action) { Action = action; }
// public IGizmoRenderer<LambdaGizmo> RegisterNewRenderer() => new Renderer();
// private class Renderer : IGizmoRenderer<LambdaGizmo>
// {
// public int ExecuteOrder => 0;
// public bool IsStaticRender => false;
// public void Prepare(Camera camera, GizmosList<LambdaGizmo> list) { }
// public void Render(Camera camera, GizmosList<LambdaGizmo> list, CommandBuffer cb)
// {
// foreach (var item in list)
// {
// item.Value.Action((item.Color, item.Timer));
// }
// }
// }
//}
#endregion
#region Mesh //TODO потестить
[IN(LINE)]
public DrawHandler Mesh<TMat>(Mesh mesh, Vector3 position, Quaternion rotation, Vector3 size)
where TMat : struct, IStaticMaterial
{
return Gizmo(new MeshGizmo<TMat>(mesh, position, rotation, size));
}
[IN(LINE)]
public DrawHandler Mesh(Mesh mesh, Vector3 position, Quaternion rotation, Vector3 size)
{
return Gizmo(new MeshGizmo<LitMat>(mesh, position, rotation, size));
}
[IN(LINE)]
public DrawHandler UnlitMesh(Mesh mesh, Vector3 position, Quaternion rotation, Vector3 size)
{
return Gizmo(new MeshGizmo<UnlitMat>(mesh, position, rotation, size));
}
[IN(LINE)]
public DrawHandler WireMesh(Mesh mesh, Vector3 position, Quaternion rotation, Vector3 size)
{
return Gizmo(new MeshGizmo<WireMat>(mesh, position, rotation, size));
}
private readonly struct MeshGizmoLayout
{
public readonly Mesh Mesh;
public readonly Quaternion Rotation;
public readonly Vector3 Position;
public readonly Vector3 Size;
public MeshGizmoLayout(Mesh mesh, Vector3 position, Quaternion rotation, Vector3 size)
{
Mesh = mesh;
Rotation = rotation;
Position = position;
Size = size;
}
}
private readonly struct MeshGizmo<TMat> : IGizmo<MeshGizmo<TMat>>
where TMat : struct, IStaticMaterial
{
public readonly Mesh Mesh;
public readonly Quaternion Rotation;
public readonly Vector3 Position;
public readonly Vector3 Size;
[IN(LINE)]
public MeshGizmo(Mesh mesh, Vector3 position, Quaternion rotation, Vector3 size)
{
Mesh = mesh;
Position = position;
Rotation = rotation;
Size = size;
}
public IGizmoRenderer<MeshGizmo<TMat>> RegisterNewRenderer() { return new Renderer(); }
private class Renderer : MeshRendererBase, IGizmoRenderer<MeshGizmo<TMat>>
{
public Renderer() : base(default(TMat)) { }
public void Prepare(Camera camera, GizmosList<MeshGizmo<TMat>> list)
{
Prepare(list);
}
public void Render(Camera camera, GizmosList<MeshGizmo<TMat>> list, CommandBuffer cb)
{
Render(cb);
}
}
}
#endregion
#region InstancingMesh
[IN(LINE)]
public DrawHandler Mesh<TMesh, TMat>(Vector3 position, Quaternion rotation, Vector3 size)
where TMesh : struct, IStaticMesh
where TMat : struct, IStaticMaterial
{
return Gizmo(new InstancingMeshGizmo<TMesh, TMat>(position, rotation, size));
}
[IN(LINE)]
public DrawHandler Mesh<TMesh>(Vector3 position, Quaternion rotation, Vector3 size)
where TMesh : struct, IStaticMesh
{
return Gizmo(new InstancingMeshGizmo<TMesh, LitMat>(position, rotation, size));
}
[IN(LINE)]
public DrawHandler UnlitMesh<TMesh>(Vector3 position, Quaternion rotation, Vector3 size)
where TMesh : struct, IStaticMesh
{
return Gizmo(new InstancingMeshGizmo<TMesh, UnlitMat>(position, rotation, size));
}
[IN(LINE)]
public DrawHandler WireMesh<TMesh>(Vector3 position, Quaternion rotation, Vector3 size)
where TMesh : struct, IStaticMesh
{
return Gizmo(new InstancingMeshGizmo<TMesh, WireMat>(position, rotation, size));
}
private readonly struct InstancingMeshGizmoLayout
{
public readonly Quaternion Rotation;
public readonly Vector3 Position;
public readonly Vector3 Size;
public InstancingMeshGizmoLayout(Vector3 position, Quaternion rotation, Vector3 size)
{
Rotation = rotation;
Position = position;
Size = size;
}
}
private readonly struct InstancingMeshGizmo<TMesh, TMat> : IGizmo<InstancingMeshGizmo<TMesh, TMat>>
where TMesh : struct, IStaticMesh
where TMat : struct, IStaticMaterial
{
public readonly Quaternion Rotation;
public readonly Vector3 Position;
public readonly Vector3 Size;
[IN(LINE)]
public InstancingMeshGizmo(Vector3 position, Quaternion rotation, Vector3 size)
{
Rotation = rotation;
Position = position;
Size = size;
}
public IGizmoRenderer<InstancingMeshGizmo<TMesh, TMat>> RegisterNewRenderer() { return new Renderer(); }
private class Renderer : InstancingMeshRendererBase, IGizmoRenderer<InstancingMeshGizmo<TMesh, TMat>>
{
public Renderer() : base(default(TMesh), default(TMat)) { }
public void Prepare(Camera camera, GizmosList<InstancingMeshGizmo<TMesh, TMat>> list)
{
Prepare(list);
}
public void Render(Camera camera, GizmosList<InstancingMeshGizmo<TMesh, TMat>> list, CommandBuffer cb)
{
Render(cb);
}
}
}
#endregion
#region Line
[IN(LINE)]
public DrawHandler Line<TMat>(Vector3 start, Vector3 end)
where TMat : struct, IStaticMaterial
{
return Gizmo(new WireLineGizmo<TMat>(start, end));
}
[IN(LINE)]
public DrawHandler Line(Vector3 start, Vector3 end)
{
return Gizmo(new WireLineGizmo<UnlitMat>(start, end));
}
private readonly struct WireLineGizmo<TMat> : IGizmo<WireLineGizmo<TMat>>
where TMat : struct, IStaticMaterial
{
public readonly Vector3 Start;
public readonly Vector3 End;
[IN(LINE)]
public WireLineGizmo(Vector3 start, Vector3 end)
{
Start = start;
End = end;
}
public IGizmoRenderer<WireLineGizmo<TMat>> RegisterNewRenderer() { return new Renderer(); }
private class Renderer : WireLineRendererBase, IGizmoRenderer<WireLineGizmo<TMat>>
{
public Renderer() : base(default(TMat)) { }
public void Prepare(Camera camera, GizmosList<WireLineGizmo<TMat>> list)
{
Prepare(list);
}
public void Render(Camera camera, GizmosList<WireLineGizmo<TMat>> list, CommandBuffer cb)
{
Render(cb);
}
}
}
#endregion
#region Text
[IN(LINE)] public DrawHandler Text(Vector3 position, object text) => Gizmo(new TextGizmo(position, text));
private readonly struct TextGizmo : IGizmo<TextGizmo>
{
public readonly Vector3 Position;
public readonly string Text;
[IN(LINE)]
public TextGizmo(Vector3 position, object text)
{
Position = position;
Text = text.ToString();
}
public IGizmoRenderer<TextGizmo> RegisterNewRenderer() { return new Renderer(); }
#region Renderer
private class Renderer : IGizmoRenderer_UnityGizmos<TextGizmo>
{
private static GUIStyle _labelStyle;
private static GUIContent _labelDummy;
public int ExecuteOrder => default(UnlitMat).GetExecuteOrder();
public bool IsStaticRender => false;
public void Prepare(Camera camera, GizmosList<TextGizmo> list) { }
public void Render(Camera camera, GizmosList<TextGizmo> list, CommandBuffer cb) { }
public void Render_UnityGizmos(Camera camera, GizmosList<TextGizmo> list)
{
#if UNITY_EDITOR
Color defaultColor = GUI.color;
if (_labelStyle == null || _labelDummy == null)
{
_labelStyle = GUI.skin.label;
_labelStyle.richText = false;
_labelDummy = new GUIContent();
}
Handles.BeginGUI();
foreach (ref readonly var item in list)
{
GUI.color = item.Color * GlobalColor;
_labelDummy.text = item.Value.Text;
if (!(HandleUtility.WorldToGUIPointWithDepth(item.Value.Position).z < 0f))
{
GUI.Label(HandleUtility.WorldPointToSizedRect(item.Value.Position, _labelDummy, _labelStyle), _labelDummy, _labelStyle);
}
}
Handles.EndGUI();
GUI.color = defaultColor;
#endif
}
}
#endregion
}
#endregion
// Base Renderers
#region MeshRendererBase
private class MeshRendererBase
{
private readonly struct GizmoData
{
public readonly Mesh Mesh;
public readonly Quaternion Rotation;
public readonly Vector3 Position;
public readonly Vector3 Size;
}
private readonly struct UnmanagedGizmoData
{
public readonly void* RawMesh;
public readonly Quaternion Rotation;
public readonly Vector3 Position;
public readonly Vector3 Size;
}
private struct PrepareJob : IJobParallelFor
{
[NativeDisableUnsafePtrRestriction]
public Gizmo<UnmanagedGizmoData>* Items;
[NativeDisableUnsafePtrRestriction]
public Matrix4x4* ResultMatrices;
[NativeDisableUnsafePtrRestriction]
public Vector4* ResultColors;
public void Execute(int index)
{
ref readonly var item = ref Items[index];
//if (item.IsSwaped == 0) { return; }
ResultMatrices[index] = Matrix4x4.TRS(item.Value.Position, item.Value.Rotation, item.Value.Size);
ResultColors[index] = item.Color;
}
}
private readonly IStaticMaterial _material;
private int _buffersLength = 0;
private PinnedArray<Matrix4x4> _matrices;
private PinnedArray<Vector4> _colors;
private PinnedArray<Gizmo<UnmanagedGizmoData>> _gizmos;
private readonly MaterialPropertyBlock _materialPropertyBlock;
private JobHandle _jobHandle;
private int _prepareCount = 0;
public virtual int ExecuteOrder => _material.GetExecuteOrder();
public virtual bool IsStaticRender => true;
public MeshRendererBase(IStaticMaterial material)
{
_materialPropertyBlock = new MaterialPropertyBlock();
_material = material;
_matrices = PinnedArray<Matrix4x4>.Pin(DummyArray<Matrix4x4>.Get());
_colors = PinnedArray<Vector4>.Pin(DummyArray<Vector4>.Get());
}
public void Prepare(GizmosList rawList)
{
var list = rawList.As<GizmoData>();
var items = list.Items;
var count = list.Count;
_prepareCount = count;
if (_buffersLength < count)
{
if (_matrices.Array != null)
{
_matrices.Dispose();
_colors.Dispose();
}
_matrices = PinnedArray<Matrix4x4>.Pin(new Matrix4x4[DebugXUtility.NextPow2(count)]);
_colors = PinnedArray<Color>.Pin(new Color[DebugXUtility.NextPow2(count)]).As<Vector4>();
_buffersLength = count;
}
if (ReferenceEquals(_gizmos.Array, items) == false)
{
if (_gizmos.Array != null)
{
_gizmos.Dispose();
}
var itemsUnmanaged = UnsafeUtility.As<Gizmo<GizmoData>[], Gizmo<UnmanagedGizmoData>[]>(ref items);
_gizmos = PinnedArray<Gizmo<UnmanagedGizmoData>>.Pin(itemsUnmanaged);
}
var job = new PrepareJob
{
Items = _gizmos.Ptr,
ResultMatrices = _matrices.Ptr,
ResultColors = _colors.Ptr,
};
_jobHandle = job.Schedule(count, 64);
}
public void Render(CommandBuffer cb)
{
Material material = _material.GetMaterial();
var items = new GizmosList<UnmanagedGizmoData>(_gizmos.Array, _prepareCount).As<GizmoData>().Items;
_materialPropertyBlock.Clear();
_jobHandle.Complete();
for (int i = 0; i < _prepareCount; i++)
{
ref readonly var item = ref items[i];
_materialPropertyBlock.SetColor(ColorPropertyID, item.Color);
cb.DrawMesh(item.Value.Mesh, _matrices.Ptr[i], material, 0, -1, _materialPropertyBlock);
}
}
}
#endregion
#region InstancingMeshRendererBase
private class InstancingMeshRendererBase
{
private readonly struct GizmoData
{
public readonly Quaternion Rotation;
public readonly Vector3 Position;
public readonly Vector3 Size;
}
private struct PrepareJob : IJobParallelFor
{
[NativeDisableUnsafePtrRestriction]
public Gizmo<GizmoData>* Items;
[NativeDisableUnsafePtrRestriction]
public Matrix4x4* ResultMatrices;
[NativeDisableUnsafePtrRestriction]
public Vector4* ResultColors;
public void Execute(int index)
{
ref readonly var item = ref Items[index];
//if (item.IsSwaped == 0) { return; }
ResultMatrices[index] = Matrix4x4.TRS(item.Value.Position, item.Value.Rotation, item.Value.Size);
ResultColors[index] = item.Color;
}
}
private readonly IStaticMesh _mesh;
private readonly IStaticMaterial _material;
private readonly MaterialPropertyBlock _materialPropertyBlock;
private int _buffersLength = 0;
private PinnedArray<Matrix4x4> _matrices;
private PinnedArray<Vector4> _colors;
private PinnedArray<Gizmo<GizmoData>> _gizmos;
private JobHandle _jobHandle;
private int _prepareCount = 0;
public InstancingMeshRendererBase(IStaticMesh mesh, IStaticMaterial material)
{
_mesh = mesh;
_material = material;
_materialPropertyBlock = new MaterialPropertyBlock();
_matrices = PinnedArray<Matrix4x4>.Pin(DummyArray<Matrix4x4>.Get());
_colors = PinnedArray<Vector4>.Pin(DummyArray<Vector4>.Get());
}
public virtual int ExecuteOrder => _material.GetExecuteOrder();
public virtual bool IsStaticRender => true;
protected void Prepare(GizmosList rawList)
{
var list = rawList.As<GizmoData>();
_prepareCount = list.Count;
var items = list.Items;
var count = list.Count;
if (_buffersLength < count)
{
_matrices.Dispose();
_colors.Dispose();
_matrices = PinnedArray<Matrix4x4>.Pin(new Matrix4x4[DebugXUtility.NextPow2(count)]);
_colors = PinnedArray<Vector4>.Pin(new Vector4[DebugXUtility.NextPow2(count)]);
_buffersLength = count;
}
if (ReferenceEquals(_gizmos.Array, items) == false)
{
if (_gizmos.Array != null)
{
_gizmos.Dispose();
}
_gizmos = PinnedArray<Gizmo<GizmoData>>.Pin(items);
}
var job = new PrepareJob
{
Items = _gizmos.Ptr,
ResultMatrices = _matrices.Ptr,
ResultColors = _colors.Ptr,
};
_jobHandle = job.Schedule(count, 64);
}
protected void Render(CommandBuffer cb)
{
Material material = _material.GetMaterial();
Mesh mesh = _mesh.GetMesh();
_materialPropertyBlock.Clear();
_jobHandle.Complete();
if (IsSupportsComputeShaders)
{
_materialPropertyBlock.SetVectorArray(ColorPropertyID, _colors.Array);
cb.DrawMeshInstanced(mesh, 0, material, -1, _matrices.Array, _prepareCount, _materialPropertyBlock);
}
else
{
for (int i = 0; i < _prepareCount; i++)
{
_materialPropertyBlock.SetColor(ColorPropertyID, _colors.Ptr[i]);
cb.DrawMesh(mesh, _matrices.Ptr[i], material, 0, -1, _materialPropertyBlock);
}
}
}
}
#endregion
#region LineRendererBase
private class WireLineRendererBase
{
private readonly struct GizmoData
{
public readonly Vector3 Start;
public readonly Vector3 End;
}
private struct PrepareJob : IJobParallelFor
{
[NativeDisableUnsafePtrRestriction]
public Gizmo<GizmoData>* Items;
[NativeDisableUnsafePtrRestriction]
public Matrix4x4* ResultMatrices;
[NativeDisableUnsafePtrRestriction]
public Vector4* ResultColors;
public void Execute(int index)
{
ref readonly var item = ref Items[index];
Vector3 halfDiff = (item.Value.End - item.Value.Start) * 0.5f;
Vector3 position = item.Value.Start + halfDiff;
ResultMatrices[index] = Matrix4x4.TRS(position, Quaternion.identity, halfDiff);
ResultColors[index] = item.Color;
}
}
private readonly IStaticMesh _mesh = default(WireLineMesh);
private readonly IStaticMaterial _material;
private readonly MaterialPropertyBlock _materialPropertyBlock;
private int _buffersLength = 0;
private PinnedArray<Matrix4x4> _matrices;
private PinnedArray<Vector4> _colors;
private PinnedArray<Gizmo<GizmoData>> _gizmos;
private JobHandle _jobHandle;
private int _prepareCount = 0;
public WireLineRendererBase(IStaticMaterial material)
{
_material = material;
_materialPropertyBlock = new MaterialPropertyBlock();
_matrices = PinnedArray<Matrix4x4>.Pin(DummyArray<Matrix4x4>.Get());
_colors = PinnedArray<Vector4>.Pin(DummyArray<Vector4>.Get());
}
public virtual int ExecuteOrder => _material.GetExecuteOrder();
public virtual bool IsStaticRender => true;
public void Prepare(GizmosList rawList)
{
var list = rawList.As<GizmoData>();
_prepareCount = list.Count;
var items = list.Items;
var count = list.Count;
if (_buffersLength < count)
{
if (_matrices.Array != null)
{
_matrices.Dispose();
_colors.Dispose();
}
_matrices = PinnedArray<Matrix4x4>.Pin(new Matrix4x4[DebugXUtility.NextPow2(count)]);
_colors = PinnedArray<Vector4>.Pin(new Vector4[DebugXUtility.NextPow2(count)]);
_buffersLength = count;
}
if (ReferenceEquals(_gizmos.Array, items) == false)
{
if (_gizmos.Array != null)
{
_gizmos.Dispose();
}
_gizmos = PinnedArray<Gizmo<GizmoData>>.Pin(items);
}
var job = new PrepareJob
{
Items = _gizmos.Ptr,
ResultMatrices = _matrices.Ptr,
ResultColors = _colors.Ptr,
};
_jobHandle = job.Schedule(count, 16);
}
public void Render(CommandBuffer cb)
{
Material material = _material.GetMaterial();
Mesh mesh = _mesh.GetMesh();
_materialPropertyBlock.Clear();
_jobHandle.Complete();
if (IsSupportsComputeShaders)
{
_materialPropertyBlock.SetVectorArray(ColorPropertyID, _colors.Array);
cb.DrawMeshInstanced(mesh, 0, material, -1, _matrices.Array, _prepareCount, _materialPropertyBlock);
}
else
{
for (int i = 0; i < _prepareCount; i++)
{
_materialPropertyBlock.SetColor(ColorPropertyID, _colors.Ptr[i]);
cb.DrawMesh(mesh, _matrices.Ptr[i], material, 0, -1, _materialPropertyBlock);
}
}
}
}
#endregion
}
}
}