// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. using System; using System.Collections.Generic; using FlaxEngine; namespace FlaxEditor { /// /// The custom data container used during collecting draw data for drawing debug visuals of selected objects. /// [HideInEditor] public class ViewportDebugDrawData { private readonly List _actors; private readonly List _highlights; private MaterialBase _highlightMaterial; private readonly List _highlightTriangles = new List(64); private Vector3[] _highlightTrianglesSet; private int[] _highlightIndicesSet; private Model _highlightTrianglesModel; internal IntPtr[] ActorsPtrs => Utils.ExtractArrayFromList(_actors); internal int ActorsCount => _actors.Count; /// /// Initializes a new instance of the class. /// /// The actors capacity. public ViewportDebugDrawData(int actorsCapacity = 0) { _actors = new List(actorsCapacity); _highlights = new List(actorsCapacity); _highlightMaterial = EditorAssets.Cache.HighlightMaterialInstance; _highlightTrianglesModel = FlaxEngine.Content.CreateVirtualAsset(); } /// /// Adds the specified actor to draw it's debug visuals. /// /// The actor. public void Add(Actor actor) { _actors.Add(FlaxEngine.Object.GetUnmanagedPtr(actor)); } /// /// Highlights the model. /// /// The model. public void HighlightModel(StaticModel model) { if (model.Model == null) return; var entries = model.Entries; for (var i = 0; i < entries.Length; i++) HighlightModel(model, i); } /// /// Highlights the model entry. /// /// The model. /// Index of the entry to highlight. public void HighlightModel(StaticModel model, int entryIndex) { _highlights.Add(new HighlightData { Target = model, EntryIndex = entryIndex }); } /// /// Highlights the brush surface. /// /// The surface. public void HighlightBrushSurface(BrushSurface surface) { surface.Brush.GetVertices(surface.Index, out var vertices); if (vertices.Length > 0) { _highlightTriangles.AddRange(vertices); } } /// /// Called when task calls event. /// /// The rendering context. public virtual void OnDraw(ref RenderContext renderContext) { if (_highlightMaterial == null || (_highlights.Count == 0 && _highlightTriangles.Count == 0) || renderContext.View.Pass == DrawPass.Depth ) return; Profiler.BeginEvent("ViewportDebugDrawData.OnDraw"); Matrix world; for (var i = 0; i < _highlights.Count; i++) { HighlightData highlight = _highlights[i]; if (highlight.Target is StaticModel staticModel) { var model = staticModel.Model; if (model == null) continue; staticModel.Transform.GetWorld(out world); var bounds = BoundingSphere.FromBox(staticModel.Box); // Pick a proper LOD int lodIndex = RenderTools.ComputeModelLOD(model, ref bounds.Center, bounds.Radius, ref renderContext); var lods = model.LODs; if (lods == null || lods.Length < lodIndex || lodIndex < 0) continue; var lod = lods[lodIndex]; // Draw meshes for (int meshIndex = 0; meshIndex < lod.Meshes.Length; meshIndex++) { if (lod.Meshes[meshIndex].MaterialSlotIndex == highlight.EntryIndex) { lod.Meshes[meshIndex].Draw(ref renderContext, _highlightMaterial, ref world); } } } } if (_highlightTriangles.Count > 0) { var mesh = _highlightTrianglesModel.LODs[0].Meshes[0]; if (!Utils.ArraysEqual(_highlightTrianglesSet, _highlightTriangles)) { _highlightIndicesSet = new int[_highlightTriangles.Count]; for (int i = 0; i < _highlightIndicesSet.Length; i++) _highlightIndicesSet[i] = i; _highlightTrianglesSet = _highlightTriangles.ToArray(); mesh.UpdateMesh(_highlightTrianglesSet, _highlightIndicesSet); } world = Matrix.Identity; mesh.Draw(ref renderContext, _highlightMaterial, ref world); } Profiler.EndEvent(); } /// /// Clears this data collector. /// public virtual void Clear() { _actors.Clear(); _highlights.Clear(); _highlightTriangles.Clear(); } /// /// Releases unmanaged and - optionally - managed resources. /// public virtual void Dispose() { _highlightMaterial = null; FlaxEngine.Object.Destroy(ref _highlightTrianglesModel); } private struct HighlightData { public object Target; public int EntryIndex; } } }