// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; using System.Collections.Generic; using FlaxEditor.Content; using FlaxEditor.Gizmo; using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.Drag; using FlaxEditor.SceneGraph; using FlaxEditor.SceneGraph.Actors; using FlaxEditor.Scripting; using FlaxEditor.Viewport.Cameras; using FlaxEditor.Viewport.Previews; using FlaxEditor.Viewport.Widgets; using FlaxEditor.Windows.Assets; using FlaxEngine; using FlaxEngine.GUI; namespace FlaxEditor.Viewport { /// /// Editor viewport used by the /// /// /// /// public class PrefabWindowViewport : PrefabPreview, IGizmoOwner { [HideInEditor] private sealed class PrefabSpritesRenderer : MainEditorGizmoViewport.EditorSpritesRenderer { public PrefabWindowViewport Viewport; /// public override bool CanRender() { return (Task.View.Flags & ViewFlags.EditorSprites) == ViewFlags.EditorSprites && Enabled; } protected override void Draw(ref RenderContext renderContext) { ViewportIconsRenderer.DrawIcons(ref renderContext, Viewport.Instance); } } private readonly PrefabWindow _window; private UpdateDelegate _update; private readonly ViewportWidgetButton _gizmoModeTranslate; private readonly ViewportWidgetButton _gizmoModeRotate; private readonly ViewportWidgetButton _gizmoModeScale; private ViewportWidgetButton _translateSnappng; private ViewportWidgetButton _rotateSnapping; private ViewportWidgetButton _scaleSnapping; private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32); private PrefabSpritesRenderer _spritesRenderer; private readonly DragAssets _dragAssets; private readonly DragActorType _dragActorType = new DragActorType(ValidateDragActorType); private readonly DragHandlers _dragHandlers = new DragHandlers(); /// /// The transform gizmo. /// public readonly TransformGizmo TransformGizmo; /// /// The selection outline postFx. /// public SelectionOutline SelectionOutline; /// /// Initializes a new instance of the class. /// /// Editor window. public PrefabWindowViewport(PrefabWindow window) : base(true) { _window = window; _window.SelectionChanged += OnSelectionChanged; Undo = window.Undo; ViewportCamera = new FPSCamera(); _dragAssets = new DragAssets(ValidateDragItem); ShowDebugDraw = true; ShowEditorPrimitives = true; var inputOptions = window.Editor.Options.Options.Input; // Prepare rendering task Task.ActorsSource = ActorsSources.CustomActors; Task.ViewFlags = ViewFlags.DefaultEditor; Task.Begin += OnBegin; Task.CollectDrawCalls += OnCollectDrawCalls; Task.PostRender += OnPostRender; // Create post effects SelectionOutline = FlaxEngine.Object.New(); SelectionOutline.SelectionGetter = () => TransformGizmo.SelectedParents; Task.AddCustomPostFx(SelectionOutline); _spritesRenderer = FlaxEngine.Object.New(); _spritesRenderer.Task = Task; _spritesRenderer.Viewport = this; Task.AddCustomPostFx(_spritesRenderer); // Add transformation gizmo TransformGizmo = new TransformGizmo(this); TransformGizmo.ApplyTransformation += ApplyTransform; TransformGizmo.ModeChanged += OnGizmoModeChanged; TransformGizmo.Duplicate += _window.Duplicate; Gizmos.Active = TransformGizmo; // Transform space widget var transformSpaceWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); var transformSpaceToggle = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Globe32, null, true) { Checked = TransformGizmo.ActiveTransformSpace == TransformGizmoBase.TransformSpace.World, TooltipText = $"Gizmo transform space (world or local) ({inputOptions.ToggleTransformSpace})", Parent = transformSpaceWidget }; transformSpaceToggle.Toggled += OnTransformSpaceToggle; transformSpaceWidget.Parent = this; // Scale snapping widget var scaleSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); var enableScaleSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.ScaleSnap32, null, true) { Checked = TransformGizmo.ScaleSnapEnabled, TooltipText = "Enable scale snapping", Parent = scaleSnappingWidget }; enableScaleSnapping.Toggled += OnScaleSnappingToggle; var scaleSnappingCM = new ContextMenu(); _scaleSnapping = new ViewportWidgetButton(TransformGizmo.ScaleSnapValue.ToString(), SpriteHandle.Invalid, scaleSnappingCM) { TooltipText = "Scale snapping values" }; for (int i = 0; i < EditorViewportScaleSnapValues.Length; i++) { var v = EditorViewportScaleSnapValues[i]; var button = scaleSnappingCM.AddButton(v.ToString()); button.Tag = v; } scaleSnappingCM.ButtonClicked += OnWidgetScaleSnapClick; scaleSnappingCM.VisibleChanged += OnWidgetScaleSnapShowHide; _scaleSnapping.Parent = scaleSnappingWidget; scaleSnappingWidget.Parent = this; // Rotation snapping widget var rotateSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); var enableRotateSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.RotateSnap32, null, true) { Checked = TransformGizmo.RotationSnapEnabled, TooltipText = "Enable rotation snapping", Parent = rotateSnappingWidget }; enableRotateSnapping.Toggled += OnRotateSnappingToggle; var rotateSnappingCM = new ContextMenu(); _rotateSnapping = new ViewportWidgetButton(TransformGizmo.RotationSnapValue.ToString(), SpriteHandle.Invalid, rotateSnappingCM) { TooltipText = "Rotation snapping values" }; for (int i = 0; i < EditorViewportRotateSnapValues.Length; i++) { var v = EditorViewportRotateSnapValues[i]; var button = rotateSnappingCM.AddButton(v.ToString()); button.Tag = v; } rotateSnappingCM.ButtonClicked += OnWidgetRotateSnapClick; rotateSnappingCM.VisibleChanged += OnWidgetRotateSnapShowHide; _rotateSnapping.Parent = rotateSnappingWidget; rotateSnappingWidget.Parent = this; // Translation snapping widget var translateSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); var enableTranslateSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Grid32, null, true) { Checked = TransformGizmo.TranslationSnapEnable, TooltipText = "Enable position snapping", Parent = translateSnappingWidget }; enableTranslateSnapping.Toggled += OnTranslateSnappingToggle; var translateSnappingCM = new ContextMenu(); _translateSnappng = new ViewportWidgetButton(TransformGizmo.TranslationSnapValue.ToString(), SpriteHandle.Invalid, translateSnappingCM) { TooltipText = "Position snapping values" }; for (int i = 0; i < EditorViewportTranslateSnapValues.Length; i++) { var v = EditorViewportTranslateSnapValues[i]; var button = translateSnappingCM.AddButton(v.ToString()); button.Tag = v; } translateSnappingCM.ButtonClicked += OnWidgetTranslateSnapClick; translateSnappingCM.VisibleChanged += OnWidgetTranslateSnapShowHide; _translateSnappng.Parent = translateSnappingWidget; translateSnappingWidget.Parent = this; // Gizmo mode widget var gizmoMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); _gizmoModeTranslate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Translate32, null, true) { Tag = TransformGizmoBase.Mode.Translate, TooltipText = $"Translate gizmo mode ({inputOptions.TranslateMode})", Checked = true, Parent = gizmoMode }; _gizmoModeTranslate.Toggled += OnGizmoModeToggle; _gizmoModeRotate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Rotate32, null, true) { Tag = TransformGizmoBase.Mode.Rotate, TooltipText = $"Rotate gizmo mode ({inputOptions.RotateMode})", Parent = gizmoMode }; _gizmoModeRotate.Toggled += OnGizmoModeToggle; _gizmoModeScale = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Scale32, null, true) { Tag = TransformGizmoBase.Mode.Scale, TooltipText = $"Scale gizmo mode ({inputOptions.ScaleMode})", Parent = gizmoMode }; _gizmoModeScale.Toggled += OnGizmoModeToggle; gizmoMode.Parent = this; _dragHandlers.Add(_dragActorType); _dragHandlers.Add(_dragAssets); // Setup input actions InputActions.Add(options => options.TranslateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate); InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate); InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale); InputActions.Add(options => options.ToggleTransformSpace, () => { OnTransformSpaceToggle(transformSpaceToggle); transformSpaceToggle.Checked = !transformSpaceToggle.Checked; }); InputActions.Add(options => options.FocusSelection, ShowSelectedActors); SetUpdate(ref _update, OnUpdate); } private void OnUpdate(float deltaTime) { for (int i = 0; i < Gizmos.Count; i++) { Gizmos[i].Update(deltaTime); } } private void OnBegin(RenderTask task, GPUContext context) { _debugDrawData.Clear(); // Collect selected objects debug shapes and visuals var selectedParents = TransformGizmo.SelectedParents; if (selectedParents.Count > 0) { for (int i = 0; i < selectedParents.Count; i++) { if (selectedParents[i].IsActiveInHierarchy) selectedParents[i].OnDebugDraw(_debugDrawData); } } } private void OnCollectDrawCalls(ref RenderContext renderContext) { _debugDrawData.OnDraw(ref renderContext); } private void OnPostRender(GPUContext context, ref RenderContext renderContext) { if (renderContext.View.Mode != ViewMode.Default) { var task = renderContext.Task; // Render editor sprites if (_spritesRenderer && _spritesRenderer.CanRender()) { _spritesRenderer.Render(context, ref renderContext, task.Output, task.Output); } // Render selection outline if (SelectionOutline && SelectionOutline.CanRender()) { // Use temporary intermediate buffer var desc = task.Output.Description; var temp = RenderTargetPool.Get(ref desc); SelectionOutline.Render(context, ref renderContext, task.Output, temp); // Copy the results back to the output context.CopyTexture(task.Output, 0, 0, 0, 0, temp, 0); RenderTargetPool.Release(temp); } } } /// /// Moves the viewport to visualize selected actors. /// public void ShowSelectedActors() { var orient = Viewport.ViewOrientation; ((FPSCamera)ViewportCamera).ShowActors(TransformGizmo.SelectedParents, ref orient); } /// public GizmosCollection Gizmos { get; } = new GizmosCollection(); /// public SceneRenderTask RenderTask => Task; /// public float ViewFarPlane => FarPlane; /// public bool IsLeftMouseButtonDown => _input.IsMouseLeftDown; /// public bool IsRightMouseButtonDown => _input.IsMouseRightDown; /// public bool IsAltKeyDown => _input.IsAltDown; /// public bool IsControlDown => _input.IsControlDown; /// public bool SnapToGround => false; /// public Float2 MouseDelta => _mouseDelta * 1000; /// public bool UseSnapping => Root.GetKey(KeyboardKeys.Control); /// public bool UseDuplicate => Root.GetKey(KeyboardKeys.Shift); /// public Undo Undo { get; } /// public RootNode SceneGraphRoot => _window.Graph.Root; /// public EditorViewport Viewport => this; /// protected override bool IsControllingMouse => Gizmos.Active?.IsControllingMouse ?? false; /// protected override void AddUpdateCallbacks(RootControl root) { base.AddUpdateCallbacks(root); root.UpdateCallbacksToAdd.Add(_update); } /// protected override void RemoveUpdateCallbacks(RootControl root) { base.RemoveUpdateCallbacks(root); root.UpdateCallbacksToRemove.Add(_update); } private void OnGizmoModeToggle(ViewportWidgetButton button) { TransformGizmo.ActiveMode = (TransformGizmoBase.Mode)(int)button.Tag; } private void OnTranslateSnappingToggle(ViewportWidgetButton button) { TransformGizmo.TranslationSnapEnable = !TransformGizmo.TranslationSnapEnable; } private void OnRotateSnappingToggle(ViewportWidgetButton button) { TransformGizmo.RotationSnapEnabled = !TransformGizmo.RotationSnapEnabled; } private void OnScaleSnappingToggle(ViewportWidgetButton button) { TransformGizmo.ScaleSnapEnabled = !TransformGizmo.ScaleSnapEnabled; } private void OnTransformSpaceToggle(ViewportWidgetButton button) { TransformGizmo.ToggleTransformSpace(); } private void OnGizmoModeChanged() { // Update all viewport widgets status var mode = TransformGizmo.ActiveMode; _gizmoModeTranslate.Checked = mode == TransformGizmoBase.Mode.Translate; _gizmoModeRotate.Checked = mode == TransformGizmoBase.Mode.Rotate; _gizmoModeScale.Checked = mode == TransformGizmoBase.Mode.Scale; } private static readonly float[] EditorViewportScaleSnapValues = { 0.05f, 0.1f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 6.0f, 8.0f, }; private void OnWidgetScaleSnapClick(ContextMenuButton button) { var v = (float)button.Tag; TransformGizmo.ScaleSnapValue = v; _scaleSnapping.Text = v.ToString(); } private void OnWidgetScaleSnapShowHide(Control control) { if (control.Visible == false) return; var ccm = (ContextMenu)control; foreach (var e in ccm.Items) { if (e is ContextMenuButton b) { var v = (float)b.Tag; b.Icon = Mathf.Abs(TransformGizmo.ScaleSnapValue - v) < 0.001f ? Style.Current.CheckBoxTick : SpriteHandle.Invalid; } } } private static readonly float[] EditorViewportRotateSnapValues = { 1.0f, 5.0f, 10.0f, 15.0f, 30.0f, 45.0f, 60.0f, 90.0f, }; private void OnWidgetRotateSnapClick(ContextMenuButton button) { var v = (float)button.Tag; TransformGizmo.RotationSnapValue = v; _rotateSnapping.Text = v.ToString(); } private void OnWidgetRotateSnapShowHide(Control control) { if (control.Visible == false) return; var ccm = (ContextMenu)control; foreach (var e in ccm.Items) { if (e is ContextMenuButton b) { var v = (float)b.Tag; b.Icon = Mathf.Abs(TransformGizmo.RotationSnapValue - v) < 0.001f ? Style.Current.CheckBoxTick : SpriteHandle.Invalid; } } } private static readonly float[] EditorViewportTranslateSnapValues = { 0.1f, 0.5f, 1.0f, 5.0f, 10.0f, 100.0f, 1000.0f, }; private void OnWidgetTranslateSnapClick(ContextMenuButton button) { var v = (float)button.Tag; TransformGizmo.TranslationSnapValue = v; _translateSnappng.Text = v.ToString(); } private void OnWidgetTranslateSnapShowHide(Control control) { if (control.Visible == false) return; var ccm = (ContextMenu)control; foreach (var e in ccm.Items) { if (e is ContextMenuButton b) { var v = (float)b.Tag; b.Icon = Mathf.Abs(TransformGizmo.TranslationSnapValue - v) < 0.001f ? Style.Current.CheckBoxTick : SpriteHandle.Invalid; } } } private void OnSelectionChanged() { Gizmos.ForEach(x => x.OnSelectionChanged(_window.Selection)); } /// /// Applies the transform to the collection of scene graph nodes. /// /// The selection. /// The translation delta. /// The rotation delta. /// The scale delta. public void ApplyTransform(List selection, ref Vector3 translationDelta, ref Quaternion rotationDelta, ref Vector3 scaleDelta) { bool applyRotation = !rotationDelta.IsIdentity; bool useObjCenter = TransformGizmo.ActivePivot == TransformGizmoBase.PivotType.ObjectCenter; Vector3 gizmoPosition = TransformGizmo.Position; // Transform selected objects for (int i = 0; i < selection.Count; i++) { var obj = selection[i]; var trans = obj.Transform; // Apply rotation if (applyRotation) { Vector3 pivotOffset = trans.Translation - gizmoPosition; if (useObjCenter || pivotOffset.IsZero) { //trans.Orientation *= rotationDelta; trans.Orientation *= Quaternion.Invert(trans.Orientation) * rotationDelta * trans.Orientation; } else { Matrix.RotationQuaternion(ref trans.Orientation, out var transWorld); Matrix.RotationQuaternion(ref rotationDelta, out var deltaWorld); Matrix world = transWorld * Matrix.Translation(pivotOffset) * deltaWorld * Matrix.Translation(-pivotOffset); trans.SetRotation(ref world); trans.Translation += world.TranslationVector; } } // Apply scale const float scaleLimit = 99_999_999.0f; trans.Scale = Float3.Clamp(trans.Scale + scaleDelta, new Float3(-scaleLimit), new Float3(scaleLimit)); // Apply translation trans.Translation += translationDelta; obj.Transform = trans; } } /// public override void Draw() { base.Draw(); // Selected UI controls outline for (var i = 0; i < _window.Selection.Count; i++) { if (_window.Selection[i]?.EditableObject is UIControl controlActor && controlActor && controlActor.Control != null) { var control = controlActor.Control; var bounds = Rectangle.FromPoints(control.PointToParent(this, Float2.Zero), control.PointToParent(this, control.Size)); Render2D.DrawRectangle(bounds, Editor.Instance.Options.Options.Visual.SelectionOutlineColor0, Editor.Instance.Options.Options.Visual.UISelectionOutlineSize); } } } /// protected override void OnLeftMouseButtonUp() { // Skip if was controlling mouse or mouse is not over the area if (_prevInput.IsControllingMouse || !Bounds.Contains(ref _viewMousePos)) return; if (TransformGizmo.IsActive) { // Ensure player is not moving objects if (TransformGizmo.ActiveAxis != TransformGizmoBase.Axis.None) return; } else { // For now just pick objects in transform gizmo mode return; } // Get mouse ray and try to hit any object var ray = MouseRay; var view = new Ray(ViewPosition, ViewDirection); var hit = _window.Graph.Root.RayCast(ref ray, ref view, out _, SceneGraphNode.RayCastData.FlagTypes.SkipColliders); // Update selection if (hit != null) { // For child actor nodes (mesh, link or sth) we need to select it's owning actor node first or any other child node (but not a child actor) if (hit is ActorChildNode actorChildNode && !actorChildNode.CanBeSelectedDirectly) { var parentNode = actorChildNode.ParentNode; bool canChildBeSelected = _window.Selection.Contains(parentNode); if (!canChildBeSelected) { for (int i = 0; i < parentNode.ChildNodes.Count; i++) { if (_window.Selection.Contains(parentNode.ChildNodes[i])) { canChildBeSelected = true; break; } } } if (!canChildBeSelected) { // Select parent hit = parentNode; } } bool addRemove = Root.GetKey(KeyboardKeys.Control); bool isSelected = _window.Selection.Contains(hit); if (addRemove) { if (isSelected) _window.Deselect(hit); else _window.Select(hit, true); } else { _window.Select(hit); } } else { _window.Deselect(); } // Keep focus Focus(); base.OnLeftMouseButtonUp(); } /// public override DragDropEffect OnDragEnter(ref Float2 location, DragData data) { var result = base.OnDragEnter(ref location, data); if (result != DragDropEffect.None) return result; return _dragHandlers.OnDragEnter(data); } private bool ValidateDragItem(ContentItem contentItem) { if (contentItem is AssetItem assetItem) { if (assetItem.OnEditorDrag(this)) return true; if (assetItem.IsOfType()) return true; } return false; } private static bool ValidateDragActorType(ScriptType actorType) { return true; } /// public override DragDropEffect OnDragMove(ref Float2 location, DragData data) { var result = base.OnDragMove(ref location, data); if (result != DragDropEffect.None) return result; return _dragHandlers.Effect; } /// public override void OnDragLeave() { _dragHandlers.OnDragLeave(); base.OnDragLeave(); } private Vector3 PostProcessSpawnedActorLocation(Actor actor, ref Vector3 hitLocation) { // Place the object //var location = hitLocation - (box.Size.Length * 0.5f) * ViewDirection; var location = hitLocation; // Apply grid snapping if enabled if (UseSnapping || TransformGizmo.TranslationSnapEnable) { float snapValue = TransformGizmo.TranslationSnapValue; location = new Vector3( (int)(location.X / snapValue) * snapValue, (int)(location.Y / snapValue) * snapValue, (int)(location.Z / snapValue) * snapValue); } return location; } private void Spawn(AssetItem item, SceneGraphNode hit, ref Float2 location, ref Vector3 hitLocation) { if (item is BinaryAssetItem binaryAssetItem) { if (typeof(MaterialBase).IsAssignableFrom(binaryAssetItem.Type)) { if (hit is StaticModelNode staticModelNode) { var staticModel = (StaticModel)staticModelNode.Actor; var ray = ConvertMouseToRay(ref location); if (staticModel.IntersectsEntry(ref ray, out _, out _, out var entryIndex)) { var material = FlaxEngine.Content.LoadAsync(item.ID); using (new UndoBlock(Undo, staticModel, "Change material")) staticModel.SetMaterial(entryIndex, material); } } return; } } { var actor = item.OnEditorDrop(this); actor.Name = item.ShortName; Spawn(actor, ref hitLocation); } } private void Spawn(Actor actor, ref Vector3 hitLocation) { actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); _window.Spawn(actor); Focus(); } private void Spawn(ScriptType item, SceneGraphNode hit, ref Vector3 hitLocation) { var actor = item.CreateInstance() as Actor; if (actor == null) { Editor.LogWarning("Failed to spawn actor of type " + item.TypeName); return; } actor.Name = item.Name; Spawn(actor, ref hitLocation); } /// /// Focuses the viewport on the current selection of the gizmo. /// public void FocusSelection() { var orientation = ViewOrientation; FocusSelection(ref orientation); } /// /// Focuses the viewport on the current selection of the gizmo. /// /// The target view orientation. public void FocusSelection(ref Quaternion orientation) { if (TransformGizmo.SelectedParents.Count == 0) return; var gizmoBounds = Gizmos.Active.FocusBounds; if (gizmoBounds != BoundingSphere.Empty) ((FPSCamera)ViewportCamera).ShowSphere(ref gizmoBounds, ref orientation); else ((FPSCamera)ViewportCamera).ShowActors(TransformGizmo.SelectedParents, ref orientation); } /// protected override void OrientViewport(ref Quaternion orientation) { if (TransformGizmo.SelectedParents.Count != 0) FocusSelection(ref orientation); else base.OrientViewport(ref orientation); } /// public override DragDropEffect OnDragDrop(ref Float2 location, DragData data) { var result = base.OnDragDrop(ref location, data); if (result != DragDropEffect.None) return result; // Check if drag sth Vector3 hitLocation = ViewPosition; SceneGraphNode hit = null; if (_dragHandlers.HasValidDrag) { // Get mouse ray and try to hit any object var ray = ConvertMouseToRay(ref location); var view = new Ray(ViewPosition, ViewDirection); hit = _window.Graph.Root.RayCast(ref ray, ref view, out var closest, SceneGraphNode.RayCastData.FlagTypes.SkipColliders); if (hit != null) { // Use hit location hitLocation = ray.Position + ray.Direction * closest; } else { // Use area in front of the viewport hitLocation = ViewPosition + ViewDirection * 100; } } // Drag assets if (_dragAssets.HasValidDrag) { result = _dragAssets.Effect; // Process items for (int i = 0; i < _dragAssets.Objects.Count; i++) { var item = _dragAssets.Objects[i]; Spawn(item, hit, ref location, ref hitLocation); } } // Drag actor type else if (_dragActorType.HasValidDrag) { result = _dragActorType.Effect; // Process items for (int i = 0; i < _dragActorType.Objects.Count; i++) { var item = _dragActorType.Objects[i]; Spawn(item, hit, ref hitLocation); } } return result; } /// public override void OnDestroy() { FlaxEngine.Object.Destroy(ref SelectionOutline); FlaxEngine.Object.Destroy(ref _spritesRenderer); base.OnDestroy(); } /// public override void DrawEditorPrimitives(GPUContext context, ref RenderContext renderContext, GPUTexture target, GPUTexture targetDepth) { // Draw gizmos for (int i = 0; i < Gizmos.Count; i++) { Gizmos[i].Draw(ref renderContext); } base.DrawEditorPrimitives(context, ref renderContext, target, targetDepth); } /// protected override void OnDebugDraw(GPUContext context, ref RenderContext renderContext) { base.OnDebugDraw(context, ref renderContext); unsafe { fixed (IntPtr* actors = _debugDrawData.ActorsPtrs) { DebugDraw.DrawActors(new IntPtr(actors), _debugDrawData.ActorsCount, false); } } } } }