diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs
index 8c71a8b02..43ec4ee78 100644
--- a/Source/Editor/Viewport/EditorViewport.cs
+++ b/Source/Editor/Viewport/EditorViewport.cs
@@ -2,6 +2,7 @@
using System;
using System.Linq;
+using FlaxEditor.Content.Settings;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Input;
using FlaxEditor.Options;
@@ -9,6 +10,9 @@ using FlaxEditor.Viewport.Cameras;
using FlaxEditor.Viewport.Widgets;
using FlaxEngine;
using FlaxEngine.GUI;
+using FlaxEngine.Utilities;
+using Newtonsoft.Json;
+using JsonSerializer = FlaxEngine.Json.JsonSerializer;
namespace FlaxEditor.Viewport
{
@@ -486,10 +490,89 @@ namespace FlaxEditor.Viewport
}
}
+ // View Layers
+ {
+ var viewLayers = ViewWidgetButtonMenu.AddChildMenu("View Layers").ContextMenu;
+ viewLayers.AddButton("Copy layers", () => Clipboard.Text = JsonSerializer.Serialize(Task.View.RenderLayersMask));
+ viewLayers.AddButton("Paste layers", () =>
+ {
+ object obj;
+ try
+ {
+ obj = JsonConvert.DeserializeObject(Clipboard.Text, typeof(LayersMask), JsonSerializer.Settings);
+ }
+ catch
+ {
+ obj = null;
+ }
+ if (obj != null && obj is LayersMask layer)
+ {
+ RenderView view = Task.View;
+ view.RenderLayersMask = layer;
+ Task.View = view;
+ }
+ });
+ viewLayers.AddButton("Reset layers", () =>
+ {
+ RenderView view = Task.View;
+ view.RenderLayersMask = LayersMask.Default;
+ Task.View = view;
+ }).Icon = Editor.Instance.Icons.Rotate32;
+ viewLayers.AddButton("Disable layers", () =>
+ {
+ RenderView view = Task.View;
+ view.RenderLayersMask = new LayersMask(0);
+ Task.View = view;
+ }).Icon = Editor.Instance.Icons.Rotate32;
+ viewLayers.AddSeparator();
+ var layers = LayersAndTagsSettings.GetCurrentLayers();
+ if (layers != null && layers.Length > 0)
+ {
+ for (int i = 0; i < layers.Length; i++)
+ {
+ var layer = layers[i];
+ var button = viewLayers.AddButton(layer);
+ button.CloseMenuOnClick = false;
+ button.Tag = 1 << i;
+ }
+ }
+ viewLayers.ButtonClicked += button =>
+ {
+ if (button.Tag != null)
+ {
+ int layerIndex = (int)button.Tag;
+ LayersMask mask = new LayersMask(layerIndex);
+ RenderView view = Task.View;
+ view.RenderLayersMask ^= mask;
+ Task.View = view;
+ button.Icon = (Task.View.RenderLayersMask & mask) != 0 ? Style.Current.CheckBoxTick : SpriteHandle.Invalid;
+ }
+ };
+ viewLayers.VisibleChanged += WidgetViewLayersShowHide;
+ }
+
// View Flags
{
var viewFlags = ViewWidgetButtonMenu.AddChildMenu("View Flags").ContextMenu;
+ viewFlags.AddButton("Copy flags", () => Clipboard.Text = JsonSerializer.Serialize(Task.ViewFlags));
+ viewFlags.AddButton("Paste flags", () =>
+ {
+ object obj;
+ try
+ {
+ obj = JsonConvert.DeserializeObject(Clipboard.Text, typeof(ViewFlags), JsonSerializer.Settings);
+ }
+ catch
+ {
+ obj = null;
+ }
+ if (obj != null && obj is ViewFlags flags)
+ {
+ Task.ViewFlags = flags;
+ }
+ });
viewFlags.AddButton("Reset flags", () => Task.ViewFlags = ViewFlags.DefaultEditor).Icon = Editor.Instance.Icons.Rotate32;
+ viewFlags.AddButton("Disable flags", () => Task.ViewFlags = ViewFlags.None).Icon = Editor.Instance.Icons.Rotate32;
viewFlags.AddSeparator();
for (int i = 0; i < EditorViewportViewFlagsValues.Length; i++)
{
@@ -513,6 +596,24 @@ namespace FlaxEditor.Viewport
// Debug View
{
var debugView = ViewWidgetButtonMenu.AddChildMenu("Debug View").ContextMenu;
+ debugView.AddButton("Copy view", () => Clipboard.Text = JsonSerializer.Serialize(Task.ViewMode));
+ debugView.AddButton("Paste view", () =>
+ {
+ object obj;
+ try
+ {
+ obj = JsonConvert.DeserializeObject(Clipboard.Text, typeof(ViewMode), JsonSerializer.Settings);
+ }
+ catch
+ {
+ obj = null;
+ }
+ if (obj != null && obj is ViewMode mode)
+ {
+ Task.ViewMode = mode;
+ }
+ });
+ debugView.AddSeparator();
for (int i = 0; i < EditorViewportViewModeValues.Length; i++)
{
ref var v = ref EditorViewportViewModeValues[i];
@@ -1591,6 +1692,25 @@ namespace FlaxEditor.Viewport
}
}
+ private void WidgetViewLayersShowHide(Control cm)
+ {
+ if (cm.Visible == false)
+ return;
+
+ var ccm = (ContextMenu)cm;
+ foreach (var e in ccm.Items)
+ {
+ if (e is ContextMenuButton b && b != null && b.Tag != null)
+ {
+ int layerIndex = (int)b.Tag;
+ LayersMask mask = new LayersMask(layerIndex);
+ b.Icon = (Task.View.RenderLayersMask & mask) != 0
+ ? Style.Current.CheckBoxTick
+ : SpriteHandle.Invalid;
+ }
+ }
+ }
+
private float GetGamepadAxis(GamepadAxis axis)
{
var value = FlaxEngine.Input.GetGamepadAxis(InputGamepadIndex.All, axis);
diff --git a/Source/Engine/Graphics/RenderView.cpp b/Source/Engine/Graphics/RenderView.cpp
index 46766c34d..c84351bdc 100644
--- a/Source/Engine/Graphics/RenderView.cpp
+++ b/Source/Engine/Graphics/RenderView.cpp
@@ -192,6 +192,8 @@ void RenderView::CopyFrom(Camera* camera, Viewport* viewport)
Frustum.GetInvMatrix(IVP);
CullingFrustum = Frustum;
RenderLayersMask = camera->RenderLayersMask;
+ Flags = camera->RenderFlags;
+ Mode = camera->RenderView;
}
void RenderView::GetWorldMatrix(const Transform& transform, Matrix& world) const
diff --git a/Source/Engine/Graphics/RenderView.cs b/Source/Engine/Graphics/RenderView.cs
index 091661514..0d35bd360 100644
--- a/Source/Engine/Graphics/RenderView.cs
+++ b/Source/Engine/Graphics/RenderView.cs
@@ -102,6 +102,8 @@ namespace FlaxEngine
NonJitteredProjection = Projection;
TemporalAAJitter = Float4.Zero;
RenderLayersMask = camera.RenderLayersMask;
+ Flags = camera.RenderFlags;
+ Mode = camera.RenderView;
UpdateCachedData();
}
diff --git a/Source/Engine/Level/Actors/Camera.cpp b/Source/Engine/Level/Actors/Camera.cpp
index f2625ca3b..2a5c44a7e 100644
--- a/Source/Engine/Level/Actors/Camera.cpp
+++ b/Source/Engine/Level/Actors/Camera.cpp
@@ -415,6 +415,8 @@ void Camera::Serialize(SerializeStream& stream, const void* otherObj)
SERIALIZE_MEMBER(Far, _far);
SERIALIZE_MEMBER(OrthoScale, _orthoScale);
SERIALIZE(RenderLayersMask);
+ SERIALIZE(RenderFlags);
+ SERIALIZE(RenderView);
}
void Camera::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
@@ -429,6 +431,8 @@ void Camera::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier
DESERIALIZE_MEMBER(Far, _far);
DESERIALIZE_MEMBER(OrthoScale, _orthoScale);
DESERIALIZE(RenderLayersMask);
+ DESERIALIZE(RenderFlags);
+ DESERIALIZE(RenderView);
}
void Camera::OnEnable()
diff --git a/Source/Engine/Level/Actors/Camera.h b/Source/Engine/Level/Actors/Camera.h
index 5a0bece33..21f13665f 100644
--- a/Source/Engine/Level/Actors/Camera.h
+++ b/Source/Engine/Level/Actors/Camera.h
@@ -7,6 +7,7 @@
#include "Engine/Core/Math/Viewport.h"
#include "Engine/Core/Math/Ray.h"
#include "Engine/Core/Types/LayersMask.h"
+#include "Engine/Graphics/Enums.h"
#include "Engine/Scripting/ScriptingObjectReference.h"
#if USE_EDITOR
#include "Engine/Content/AssetReference.h"
@@ -134,6 +135,18 @@ public:
API_FIELD(Attributes="EditorOrder(100), EditorDisplay(\"Camera\")")
LayersMask RenderLayersMask;
+ ///
+ /// Frame rendering flags used to switch between graphics features for this camera.
+ ///
+ API_FIELD(Attributes = "EditorOrder(110), EditorDisplay(\"Camera\")")
+ ViewFlags RenderFlags = ViewFlags::DefaultGame;
+
+ ///
+ /// Describes frame rendering modes for this camera.
+ ///
+ API_FIELD(Attributes = "EditorOrder(120), EditorDisplay(\"Camera\")")
+ ViewMode RenderView = ViewMode::Default;
+
public:
///
/// Projects the point from 3D world-space to game window coordinates (in screen pixels for default viewport calculated from ).