diff --git a/Source/Editor/Content/Proxy/PrefabProxy.cs b/Source/Editor/Content/Proxy/PrefabProxy.cs index 18860995e..c0c4e5c88 100644 --- a/Source/Editor/Content/Proxy/PrefabProxy.cs +++ b/Source/Editor/Content/Proxy/PrefabProxy.cs @@ -89,7 +89,7 @@ namespace FlaxEditor.Content // Cleanup it after usage Object.Destroy(actor, 20.0f); } - else if (actor.Scene != null) + else if (actor.HasScene) { // Create prefab with identity transform so the actor instance on a level will have it customized resetTransform = true; diff --git a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs index 1561e6245..bdbf22ee9 100644 --- a/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ActorEditor.cs @@ -291,7 +291,7 @@ namespace FlaxEditor.CustomEditors.Dedicated if (editor.ChildrenEditors.Count == 0 || (isRefEdited && editor is CollectionEditor)) result = CreateDiffNode(editor); bool isScriptEditorWithRefValue = editor is ScriptsEditor && editor.Values.HasReferenceValue; - bool isActorEditorInLevel = editor is ActorEditor && editor.Values[0] is Actor actor && actor.IsPrefabRoot && actor.Scene != null; + bool isActorEditorInLevel = editor is ActorEditor && editor.Values[0] is Actor actor && actor.IsPrefabRoot && actor.HasScene; for (int i = 0; i < editor.ChildrenEditors.Count; i++) { var childEditor = editor.ChildrenEditors[i]; diff --git a/Source/Editor/GUI/Tree/TreeNode.cs b/Source/Editor/GUI/Tree/TreeNode.cs index 36331d6d2..dafd3a368 100644 --- a/Source/Editor/GUI/Tree/TreeNode.cs +++ b/Source/Editor/GUI/Tree/TreeNode.cs @@ -38,7 +38,6 @@ namespace FlaxEditor.GUI.Tree private bool _isMouseDown; private float _mouseDownTime; private Float2 _mouseDownPos; - private Color _cachedTextColor; private DragItemPositioning _dragOverMode; private bool _isDragOverHeader; @@ -604,9 +603,6 @@ namespace FlaxEditor.GUI.Tree /// public override void Update(float deltaTime) { - // Cache text color - _cachedTextColor = CacheTextColor(); - // Drop/down animation if (_animationProgress < 1.0f) { @@ -676,7 +672,8 @@ namespace FlaxEditor.GUI.Tree } // Draw text - Render2D.DrawText(TextFont.GetFont(), _text, textRect, _cachedTextColor, TextAlignment.Near, TextAlignment.Center); + Color textColor = CacheTextColor(); + Render2D.DrawText(TextFont.GetFont(), _text, textRect, textColor, TextAlignment.Near, TextAlignment.Center); // Draw drag and drop effect if (IsDragOver && _tree.DraggedOverNode == this) @@ -712,6 +709,71 @@ namespace FlaxEditor.GUI.Tree } } + /// + protected override void DrawChildren() + { + // Draw all visible child controls + var children = _children; + if (children.Count == 0) + return; + + if (CullChildren) + { + Render2D.PeekClip(out var globalClipping); + Render2D.PeekTransform(out var globalTransform); + + // Try to estimate the rough location of the first node, assuming the node height is constant + var firstChildGlobalRect = GetChildGlobalRectangle(children[0], ref globalTransform); + var firstVisibleChild = Math.Clamp((int)Math.Floor((globalClipping.Y - firstChildGlobalRect.Top) / firstChildGlobalRect.Height) + 1, 0, children.Count - 1); + if (GetChildGlobalRectangle(children[firstVisibleChild], ref globalTransform).Top > globalClipping.Top) + { + // Overshoot... + for (; firstVisibleChild > 0; firstVisibleChild--) + { + var child = children[firstVisibleChild]; + if (GetChildGlobalRectangle(child, ref globalTransform).Top < globalClipping.Top) + break; + } + } + + for (int i = firstVisibleChild; i < children.Count; i++) + { + var child = children[i]; + if (child.Visible) + { + var childGlobalRect = GetChildGlobalRectangle(child, ref globalTransform); + if (globalClipping.Intersects(ref childGlobalRect)) + { + Render2D.PushTransform(ref child._cachedTransform); + child.Draw(); + Render2D.PopTransform(); + } + else + break; + } + } + + static Rectangle GetChildGlobalRectangle(Control control, ref Matrix3x3 globalTransform) + { + Matrix3x3.Multiply(ref control._cachedTransform, ref globalTransform, out var globalChildTransform); + return new Rectangle(globalChildTransform.M31, globalChildTransform.M32, control.Width * globalChildTransform.M11, control.Height * globalChildTransform.M22); + } + } + else + { + for (int i = 0; i < children.Count; i++) + { + var child = children[i]; + if (child.Visible) + { + Render2D.PushTransform(ref child._cachedTransform); + child.Draw(); + Render2D.PopTransform(); + } + } + } + } + /// public override bool OnMouseDown(Float2 location, MouseButton button) { @@ -1104,7 +1166,6 @@ namespace FlaxEditor.GUI.Tree { // TODO: perform layout for any non-TreeNode controls _cachedHeight = _headerHeight; - _cachedTextColor = CacheTextColor(); Size = new Float2(width, _headerHeight); } @@ -1154,7 +1215,6 @@ namespace FlaxEditor.GUI.Tree } _cachedHeight = height; - _cachedTextColor = CacheTextColor(); Height = Mathf.Max(_headerHeight, y); } diff --git a/Source/Editor/Modules/PrefabsModule.cs b/Source/Editor/Modules/PrefabsModule.cs index e0e464c04..e0ae29299 100644 --- a/Source/Editor/Modules/PrefabsModule.cs +++ b/Source/Editor/Modules/PrefabsModule.cs @@ -227,7 +227,7 @@ namespace FlaxEditor.Modules // When applying changes to prefab from actor in level ignore it's root transformation (see ActorEditor.ProcessDiff) var originalTransform = instance.LocalTransform; - if (instance.IsPrefabRoot && instance.Scene != null) + if (instance.IsPrefabRoot && instance.HasScene) instance.LocalTransform = prefab.GetDefaultInstance().Transform; // Call backend diff --git a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs index 6056cf68b..77e441848 100644 --- a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs +++ b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs @@ -68,7 +68,7 @@ namespace FlaxEditor.SceneGraph.GUI Visible = (actor.HideFlags & HideFlags.HideInHierarchy) == 0; // Pick the correct id when inside a prefab window. - var id = actor.HasPrefabLink && actor.Scene == null ? actor.PrefabObjectID : actor.ID; + var id = actor.HasPrefabLink && !actor.HasScene ? actor.PrefabObjectID : actor.ID; if (Editor.Instance.ProjectCache.IsExpandedActor(ref id)) { Expand(true); @@ -291,7 +291,7 @@ namespace FlaxEditor.SceneGraph.GUI return Style.Current.ForegroundGrey; } - if (actor.Scene != null && Editor.Instance.StateMachine.IsPlayMode && actor.IsStatic) + if (actor.HasScene && Editor.Instance.StateMachine.IsPlayMode && actor.IsStatic) { // Static return color * 0.85f; @@ -366,7 +366,7 @@ namespace FlaxEditor.SceneGraph.GUI if (!IsLayoutLocked && actor) { // Pick the correct id when inside a prefab window. - var id = actor.HasPrefabLink && actor.Scene == null ? actor.PrefabObjectID : actor.ID; + var id = actor.HasPrefabLink && !actor.HasScene ? actor.PrefabObjectID : actor.ID; Editor.Instance.ProjectCache.SetExpandedActor(ref id, IsExpanded); } } @@ -640,8 +640,8 @@ namespace FlaxEditor.SceneGraph.GUI private bool ValidateDragScript(Script script) { // Reject dragging scripts not linked to scene (eg. from prefab) or in the opposite way - var thisHasScene = Actor.Scene != null; - var otherHasScene = script.Scene != null; + var thisHasScene = Actor.HasScene; + var otherHasScene = script.HasScene; if (thisHasScene != otherHasScene) return false; diff --git a/Source/Editor/SceneGraph/LocalSceneGraph.cs b/Source/Editor/SceneGraph/LocalSceneGraph.cs index f0f99a6ed..3c92c9bc8 100644 --- a/Source/Editor/SceneGraph/LocalSceneGraph.cs +++ b/Source/Editor/SceneGraph/LocalSceneGraph.cs @@ -91,7 +91,7 @@ namespace FlaxEditor.SceneGraph private void OnActorSpawned(Actor actor) { // Skip actors from game - if (actor.Scene != null) + if (actor.HasScene) return; // Check if it has parent diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h index fdbcd1bd0..98045fc85 100644 --- a/Source/Engine/Level/Actor.h +++ b/Source/Engine/Level/Actor.h @@ -382,6 +382,15 @@ public: return _isActiveInHierarchy != 0; } + /// + /// Gets value indicating if actor is in a scene. + /// + API_PROPERTY(Attributes="HideInEditor, NoSerialize") + FORCE_INLINE bool HasScene() const + { + return _scene != nullptr; + } + /// /// Returns true if object is fully static on the scene, otherwise false. /// diff --git a/Source/Engine/Scripting/Script.cs b/Source/Engine/Scripting/Script.cs index f7d6c0242..b980baf3f 100644 --- a/Source/Engine/Scripting/Script.cs +++ b/Source/Engine/Scripting/Script.cs @@ -17,6 +17,12 @@ namespace FlaxEngine } } + /// + /// Gets value indicating if the actor owning the script is in a scene. + /// + [HideInEditor, NoSerialize] + public bool HasScene => Actor?.HasScene ?? false; + /// /// Gets or sets the world space transformation of the actors owning this script. ///