Merge branch 'master' into 1.5

This commit is contained in:
Wojtek Figat
2022-11-22 19:58:53 +01:00
40 changed files with 400 additions and 206 deletions

View File

@@ -18,6 +18,7 @@ float TimeParam;
float4 ViewInfo; float4 ViewInfo;
float4 ScreenSize; float4 ScreenSize;
float4 TemporalAAJitter; float4 TemporalAAJitter;
float4x4 InverseViewProjectionMatrix;
@1META_CB_END @1META_CB_END
// Shader resources // Shader resources
@@ -62,6 +63,14 @@ MaterialInput GetMaterialInput(PixelInput input)
return result; return result;
} }
// Gets world space position at given pixel coordinate with given device depth
float3 GetWorldPos(float2 uv, float deviceDepth)
{
float4 clipPos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), deviceDepth, 1.0);
float4 wsPos = mul(clipPos, InverseViewProjectionMatrix);
return wsPos.xyz / wsPos.w;
}
// Transforms a vector from tangent space to world space // Transforms a vector from tangent space to world space
float3 TransformTangentVectorToWorld(MaterialInput input, float3 tangentVector) float3 TransformTangentVectorToWorld(MaterialInput input, float3 tangentVector)
{ {

View File

@@ -11,6 +11,16 @@ for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer
goto End goto End
) )
) )
for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath') do (
if exist "%%i\MSBuild\15.0\Bin\MSBuild.exe" (
set MSBUILD_PATH="%%i\MSBuild\15.0\Bin\MSBuild.exe"
goto End
)
if exist "%%i\MSBuild\Current\Bin\MSBuild.exe" (
set MSBUILD_PATH="%%i\MSBuild\Current\Bin\MSBuild.exe"
goto End
)
)
:VsWhereNotFound :VsWhereNotFound
if exist "%ProgramFiles(x86)%\MSBuild\14.0\bin\MSBuild.exe" ( if exist "%ProgramFiles(x86)%\MSBuild\14.0\bin\MSBuild.exe" (

View File

@@ -11,6 +11,7 @@ namespace FlaxEditor.Content
/// A <see cref="AnimationGraphFunction"/> asset proxy object. /// A <see cref="AnimationGraphFunction"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Animation/Animation Graph Function")]
public class AnimationGraphFunctionProxy : BinaryAssetProxy public class AnimationGraphFunctionProxy : BinaryAssetProxy
{ {
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -11,6 +11,7 @@ namespace FlaxEditor.Content
/// A <see cref="AnimationGraph"/> asset proxy object. /// A <see cref="AnimationGraph"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Animation/Animation Graph")]
public class AnimationGraphProxy : BinaryAssetProxy public class AnimationGraphProxy : BinaryAssetProxy
{ {
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -14,6 +14,7 @@ namespace FlaxEditor.Content
/// A <see cref="Animation"/> asset proxy object. /// A <see cref="Animation"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Animation/Animation")]
public class AnimationProxy : BinaryAssetProxy public class AnimationProxy : BinaryAssetProxy
{ {
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -12,6 +12,7 @@ namespace FlaxEditor.Content
/// Context proxy object for C# script files. /// Context proxy object for C# script files.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" /> /// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" />
[ContentContextMenu("New/C# Script")]
public class CSharpScriptProxy : ScriptProxy public class CSharpScriptProxy : ScriptProxy
{ {
/// <summary> /// <summary>

View File

@@ -38,6 +38,7 @@ namespace FlaxEditor.Content
/// A <see cref="CollisionData"/> asset proxy object. /// A <see cref="CollisionData"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Physics/Collision Data")]
class CollisionDataProxy : BinaryAssetProxy class CollisionDataProxy : BinaryAssetProxy
{ {
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -75,6 +75,7 @@ namespace FlaxEditor.Content
/// Context proxy object for C++ script files. /// Context proxy object for C++ script files.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" /> /// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" />
[ContentContextMenu("New/C++/C++ Script")]
public class CppScriptProxy : CppProxy public class CppScriptProxy : CppProxy
{ {
/// <inheritdoc /> /// <inheritdoc />
@@ -98,6 +99,7 @@ namespace FlaxEditor.Content
/// Context proxy object for C++ Json Asset files. /// Context proxy object for C++ Json Asset files.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" /> /// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" />
[ContentContextMenu("New/C++/C++ Function Library")]
public class CppStaticClassProxy : CppProxy public class CppStaticClassProxy : CppProxy
{ {
/// <inheritdoc /> /// <inheritdoc />
@@ -115,6 +117,7 @@ namespace FlaxEditor.Content
/// Context proxy object for C++ Json Asset files. /// Context proxy object for C++ Json Asset files.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" /> /// <seealso cref="FlaxEditor.Content.CSharpScriptProxy" />
[ContentContextMenu("New/C++/C++ Json Asset")]
public class CppAssetProxy : CppProxy public class CppAssetProxy : CppProxy
{ {
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -11,6 +11,7 @@ namespace FlaxEditor.Content
/// A <see cref="GameplayGlobals"/> asset proxy object. /// A <see cref="GameplayGlobals"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Gameplay Globals")]
public class GameplayGlobalsProxy : BinaryAssetProxy public class GameplayGlobalsProxy : BinaryAssetProxy
{ {
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -22,6 +22,7 @@ namespace FlaxEditor.Content
/// Json assets proxy. /// Json assets proxy.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.JsonAssetBaseProxy" /> /// <seealso cref="FlaxEditor.Content.JsonAssetBaseProxy" />
[ContentContextMenu("New/Json Asset")]
public abstract class JsonAssetProxy : JsonAssetBaseProxy public abstract class JsonAssetProxy : JsonAssetBaseProxy
{ {
/// <summary> /// <summary>

View File

@@ -11,6 +11,7 @@ namespace FlaxEditor.Content
/// A <see cref="MaterialFunction"/> asset proxy object. /// A <see cref="MaterialFunction"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Material/Material Function")]
public class MaterialFunctionProxy : BinaryAssetProxy public class MaterialFunctionProxy : BinaryAssetProxy
{ {
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -14,6 +14,7 @@ namespace FlaxEditor.Content
/// A <see cref="MaterialInstance"/> asset proxy object. /// A <see cref="MaterialInstance"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Material/Material Instance")]
public class MaterialInstanceProxy : BinaryAssetProxy public class MaterialInstanceProxy : BinaryAssetProxy
{ {
private MaterialPreview _preview; private MaterialPreview _preview;

View File

@@ -15,6 +15,7 @@ namespace FlaxEditor.Content
/// A <see cref="Material"/> asset proxy object. /// A <see cref="Material"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Material/Material")]
public class MaterialProxy : BinaryAssetProxy public class MaterialProxy : BinaryAssetProxy
{ {
private MaterialPreview _preview; private MaterialPreview _preview;

View File

@@ -11,6 +11,7 @@ namespace FlaxEditor.Content
/// A <see cref="ParticleEmitterFunction"/> asset proxy object. /// A <see cref="ParticleEmitterFunction"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Particles/Particle Emitter Function")]
public class ParticleEmitterFunctionProxy : BinaryAssetProxy public class ParticleEmitterFunctionProxy : BinaryAssetProxy
{ {
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -15,6 +15,7 @@ namespace FlaxEditor.Content
/// A <see cref="ParticleEmitter"/> asset proxy object. /// A <see cref="ParticleEmitter"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Particles/Particle Emitter")]
public class ParticleEmitterProxy : BinaryAssetProxy public class ParticleEmitterProxy : BinaryAssetProxy
{ {
private ParticleEmitterPreview _preview; private ParticleEmitterPreview _preview;

View File

@@ -39,6 +39,7 @@ namespace FlaxEditor.Content
/// A <see cref="ParticleSystem"/> asset proxy object. /// A <see cref="ParticleSystem"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Particles/Particle System")]
public class ParticleSystemProxy : BinaryAssetProxy public class ParticleSystemProxy : BinaryAssetProxy
{ {
private ParticleSystemPreview _preview; private ParticleSystemPreview _preview;

View File

@@ -15,6 +15,7 @@ namespace FlaxEditor.Content
/// Content proxy for <see cref="PrefabItem"/>. /// Content proxy for <see cref="PrefabItem"/>.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.JsonAssetBaseProxy" /> /// <seealso cref="FlaxEditor.Content.JsonAssetBaseProxy" />
[ContentContextMenu("New/Prefab")]
public sealed class PrefabProxy : JsonAssetBaseProxy public sealed class PrefabProxy : JsonAssetBaseProxy
{ {
private PrefabPreview _preview; private PrefabPreview _preview;

View File

@@ -10,6 +10,7 @@ namespace FlaxEditor.Content
/// Content proxy for <see cref="SceneItem"/>. /// Content proxy for <see cref="SceneItem"/>.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.JsonAssetBaseProxy" /> /// <seealso cref="FlaxEditor.Content.JsonAssetBaseProxy" />
[ContentContextMenu("New/Scene")]
public sealed class SceneProxy : JsonAssetBaseProxy public sealed class SceneProxy : JsonAssetBaseProxy
{ {
/// <summary> /// <summary>

View File

@@ -11,6 +11,7 @@ namespace FlaxEditor.Content
/// Content proxy for json settings assets (e.g <see cref="GameSettings"/> or <see cref="TimeSettings"/>). /// Content proxy for json settings assets (e.g <see cref="GameSettings"/> or <see cref="TimeSettings"/>).
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.JsonAssetProxy" /> /// <seealso cref="FlaxEditor.Content.JsonAssetProxy" />
[ContentContextMenu("New/Settings")]
public class SettingsProxy : JsonAssetProxy public class SettingsProxy : JsonAssetProxy
{ {
private readonly Type _type; private readonly Type _type;

View File

@@ -13,6 +13,7 @@ namespace FlaxEditor.Content
/// Context proxy object for shader source files (represented by <see cref="ShaderSourceItem"/>). /// Context proxy object for shader source files (represented by <see cref="ShaderSourceItem"/>).
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.ContentProxy" /> /// <seealso cref="FlaxEditor.Content.ContentProxy" />
[ContentContextMenu("New/Shader Source")]
public class ShaderSourceProxy : ContentProxy public class ShaderSourceProxy : ContentProxy
{ {
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -11,6 +11,7 @@ namespace FlaxEditor.Content
/// A <see cref="SkeletonMask"/> asset proxy object. /// A <see cref="SkeletonMask"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Animation/Skeleton Mask")]
public class SkeletonMaskProxy : BinaryAssetProxy public class SkeletonMaskProxy : BinaryAssetProxy
{ {
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -15,6 +15,7 @@ namespace FlaxEditor.Content
/// A <see cref="VisualScript"/> asset proxy object. /// A <see cref="VisualScript"/> asset proxy object.
/// </summary> /// </summary>
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" /> /// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
[ContentContextMenu("New/Visual Script")]
public class VisualScriptProxy : BinaryAssetProxy, IScriptTypesContainer public class VisualScriptProxy : BinaryAssetProxy, IScriptTypesContainer
{ {
internal VisualScriptProxy() internal VisualScriptProxy()

View File

@@ -94,6 +94,12 @@ namespace FlaxEditor.CustomEditors.Dedicated
} }
Refresh(); Refresh();
var parameters = effect.Parameters; var parameters = effect.Parameters;
if (parameters.Length == 0)
{
base.RefreshRootChild();
return;
}
for (int i = 0; i < ChildrenEditors.Count; i++) for (int i = 0; i < ChildrenEditors.Count; i++)
{ {
if (_isActive != effect.IsActive || _parametersVersion != effect.ParametersVersion) if (_isActive != effect.IsActive || _parametersVersion != effect.ParametersVersion)

View File

@@ -248,7 +248,7 @@ namespace FlaxEditor.GUI.Input
// Hide cursor and cache location // Hide cursor and cache location
Cursor = CursorType.Hidden; Cursor = CursorType.Hidden;
_mouseClickedPosition = location; _mouseClickedPosition = PointToWindow(location);
_cursorChanged = true; _cursorChanged = true;
SlidingStart?.Invoke(); SlidingStart?.Invoke();
@@ -293,7 +293,7 @@ namespace FlaxEditor.GUI.Input
if (button == MouseButton.Left && _isSliding) if (button == MouseButton.Left && _isSliding)
{ {
// End sliding and return mouse to original location // End sliding and return mouse to original location
Root.MousePosition = ScreenPos + _mouseClickedPosition; RootWindow.MousePosition = _mouseClickedPosition;
EndSliding(); EndSliding();
return true; return true;
} }

View File

@@ -57,7 +57,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing
_list.Clear(); _list.Clear();
_hasValidData = true; _hasValidData = true;
Editor.Log("Searching for valid " + _type); Editor.Log("Searching for valid " + (_type != ScriptType.Null ? _type.ToString() : "types"));
Profiler.BeginEvent("Search " + _type); Profiler.BeginEvent("Search " + _type);
var start = DateTime.Now; var start = DateTime.Now;

View File

@@ -738,9 +738,10 @@ namespace FlaxEditor.Utilities
var settings = CreateWindowSettings.Default; var settings = CreateWindowSettings.Default;
settings.ActivateWhenFirstShown = true; settings.ActivateWhenFirstShown = true;
settings.AllowMaximize = false; settings.AllowMaximize = true;
settings.AllowMinimize = false; settings.AllowMinimize = false;
settings.HasSizingFrame = false; settings.HasSizingFrame = true;
settings.HasBorder = true;
settings.StartPosition = WindowStartPosition.CenterParent; settings.StartPosition = WindowStartPosition.CenterParent;
settings.Size = new Float2(500, 600) * (parentWindow?.DpiScale ?? Platform.DpiScale); settings.Size = new Float2(500, 600) * (parentWindow?.DpiScale ?? Platform.DpiScale);
settings.Parent = parentWindow; settings.Parent = parentWindow;
@@ -754,10 +755,25 @@ namespace FlaxEditor.Utilities
}; };
copyButton.Clicked += () => Clipboard.Text = source; copyButton.Clicked += () => Clipboard.Text = source;
var sourceTextBox = new TextBox(true, 2, copyButton.Bottom + 4, settings.Size.X - 4); var backPanel = new Panel
sourceTextBox.Height = settings.Size.Y - sourceTextBox.Top - 2; {
AnchorPreset = AnchorPresets.StretchAll,
Offsets = new Margin(0, 0, copyButton.Bottom + 4, 0),
ScrollBars = ScrollBars.Both,
IsScrollable = true,
Parent = dialog.GUI,
};
var sourceTextBox = new TextBox(true, 0, 0, 0);
sourceTextBox.Parent = backPanel;
sourceTextBox.AnchorPreset = AnchorPresets.HorizontalStretchTop;
sourceTextBox.Text = source; sourceTextBox.Text = source;
sourceTextBox.Parent = dialog.GUI; sourceTextBox.Height = sourceTextBox.TextSize.Y;
sourceTextBox.IsReadOnly = true;
sourceTextBox.IsMultilineScrollable = false;
sourceTextBox.IsScrollable = true;
backPanel.SizeChanged += control => { sourceTextBox.Width = (control.Size.X >= sourceTextBox.TextSize.X) ? control.Width : sourceTextBox.TextSize.X + 30; };
dialog.Show(); dialog.Show();
dialog.Focus(); dialog.Focus();

View File

@@ -539,6 +539,7 @@ namespace FlaxEditor.Viewport
// Orthographic // Orthographic
{ {
var ortho = ViewWidgetButtonMenu.AddButton("Orthographic"); var ortho = ViewWidgetButtonMenu.AddButton("Orthographic");
ortho.CloseMenuOnClick = false;
var orthoValue = new CheckBox(90, 2, _isOrtho) var orthoValue = new CheckBox(90, 2, _isOrtho)
{ {
Parent = ortho Parent = ortho
@@ -578,6 +579,7 @@ namespace FlaxEditor.Viewport
// Field of View // Field of View
{ {
var fov = ViewWidgetButtonMenu.AddButton("Field Of View"); var fov = ViewWidgetButtonMenu.AddButton("Field Of View");
fov.CloseMenuOnClick = false;
var fovValue = new FloatValueBox(1, 90, 2, 70.0f, 35.0f, 160.0f, 0.1f) var fovValue = new FloatValueBox(1, 90, 2, 70.0f, 35.0f, 160.0f, 0.1f)
{ {
Parent = fov Parent = fov
@@ -594,6 +596,7 @@ namespace FlaxEditor.Viewport
// Ortho Scale // Ortho Scale
{ {
var orthoSize = ViewWidgetButtonMenu.AddButton("Ortho Scale"); var orthoSize = ViewWidgetButtonMenu.AddButton("Ortho Scale");
orthoSize.CloseMenuOnClick = false;
var orthoSizeValue = new FloatValueBox(_orthoSize, 90, 2, 70.0f, 0.001f, 100000.0f, 0.01f) var orthoSizeValue = new FloatValueBox(_orthoSize, 90, 2, 70.0f, 0.001f, 100000.0f, 0.01f)
{ {
Parent = orthoSize Parent = orthoSize
@@ -610,6 +613,7 @@ namespace FlaxEditor.Viewport
// Near Plane // Near Plane
{ {
var nearPlane = ViewWidgetButtonMenu.AddButton("Near Plane"); var nearPlane = ViewWidgetButtonMenu.AddButton("Near Plane");
nearPlane.CloseMenuOnClick = false;
var nearPlaneValue = new FloatValueBox(2.0f, 90, 2, 70.0f, 0.001f, 1000.0f) var nearPlaneValue = new FloatValueBox(2.0f, 90, 2, 70.0f, 0.001f, 1000.0f)
{ {
Parent = nearPlane Parent = nearPlane
@@ -621,6 +625,7 @@ namespace FlaxEditor.Viewport
// Far Plane // Far Plane
{ {
var farPlane = ViewWidgetButtonMenu.AddButton("Far Plane"); var farPlane = ViewWidgetButtonMenu.AddButton("Far Plane");
farPlane.CloseMenuOnClick = false;
var farPlaneValue = new FloatValueBox(1000, 90, 2, 70.0f, 10.0f) var farPlaneValue = new FloatValueBox(1000, 90, 2, 70.0f, 10.0f)
{ {
Parent = farPlane Parent = farPlane
@@ -632,6 +637,7 @@ namespace FlaxEditor.Viewport
// Brightness // Brightness
{ {
var brightness = ViewWidgetButtonMenu.AddButton("Brightness"); var brightness = ViewWidgetButtonMenu.AddButton("Brightness");
brightness.CloseMenuOnClick = false;
var brightnessValue = new FloatValueBox(1.0f, 90, 2, 70.0f, 0.001f, 10.0f, 0.001f) var brightnessValue = new FloatValueBox(1.0f, 90, 2, 70.0f, 0.001f, 10.0f, 0.001f)
{ {
Parent = brightness Parent = brightness
@@ -643,6 +649,7 @@ namespace FlaxEditor.Viewport
// Resolution // Resolution
{ {
var resolution = ViewWidgetButtonMenu.AddButton("Resolution"); var resolution = ViewWidgetButtonMenu.AddButton("Resolution");
resolution.CloseMenuOnClick = false;
var resolutionValue = new FloatValueBox(1.0f, 90, 2, 70.0f, 0.1f, 4.0f, 0.001f) var resolutionValue = new FloatValueBox(1.0f, 90, 2, 70.0f, 0.1f, 4.0f, 0.001f)
{ {
Parent = resolution Parent = resolution
@@ -654,6 +661,7 @@ namespace FlaxEditor.Viewport
// Invert Panning // Invert Panning
{ {
var invert = ViewWidgetButtonMenu.AddButton("Invert Panning"); var invert = ViewWidgetButtonMenu.AddButton("Invert Panning");
invert.CloseMenuOnClick = false;
var invertValue = new CheckBox(90, 2, _invertPanning) var invertValue = new CheckBox(90, 2, _invertPanning)
{ {
Parent = invert Parent = invert

View File

@@ -263,21 +263,22 @@ namespace FlaxEditor.Windows.Assets
} }
if (attribute == null) if (attribute == null)
continue; continue;
var splitPath = attribute.Path.Split('/'); var parts = attribute.Path.Split('/');
ContextMenuChildMenu childCM = null; ContextMenuChildMenu childCM = null;
bool mainCM = true; bool mainCM = true;
for (int i = 0; i < splitPath?.Length; i++) for (int i = 0; i < parts.Length; i++)
{ {
if (i == splitPath.Length - 1) var part = parts[i].Trim();
if (i == parts.Length - 1)
{ {
if (mainCM) if (mainCM)
{ {
contextMenu.AddButton(splitPath[i].Trim(), () => Spawn(actorType.Type)); contextMenu.AddButton(part, () => Spawn(actorType.Type));
mainCM = false; mainCM = false;
} }
else else if (childCM != null)
{ {
childCM?.ContextMenu.AddButton(splitPath[i].Trim(), () => Spawn(actorType.Type)); childCM.ContextMenu.AddButton(part, () => Spawn(actorType.Type));
childCM.ContextMenu.AutoSort = true; childCM.ContextMenu.AutoSort = true;
} }
} }
@@ -285,17 +286,18 @@ namespace FlaxEditor.Windows.Assets
{ {
if (mainCM) if (mainCM)
{ {
childCM = contextMenu.GetOrAddChildMenu(splitPath[i].Trim()); childCM = contextMenu.GetOrAddChildMenu(part);
childCM.ContextMenu.AutoSort = true;
mainCM = false; mainCM = false;
} }
else else if (childCM != null)
{ {
childCM = childCM?.ContextMenu.GetOrAddChildMenu(splitPath[i].Trim()); childCM = childCM.ContextMenu.GetOrAddChildMenu(part);
}
childCM.ContextMenu.AutoSort = true; childCM.ContextMenu.AutoSort = true;
} }
} }
} }
}
// Custom options // Custom options
bool showCustomNodeOptions = Editor.SceneEditing.Selection.Count == 1; bool showCustomNodeOptions = Editor.SceneEditing.Selection.Count == 1;

View File

@@ -3,6 +3,7 @@
using System; using System;
using FlaxEditor.Content; using FlaxEditor.Content;
using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.Scripting;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.Assertions; using FlaxEngine.Assertions;
using FlaxEngine.Json; using FlaxEngine.Json;
@@ -39,7 +40,6 @@ namespace FlaxEditor.Windows
// Create context menu // Create context menu
ContextMenuButton b; ContextMenuButton b;
ContextMenuChildMenu c;
ContextMenu cm = new ContextMenu ContextMenu cm = new ContextMenu
{ {
Tag = item Tag = item
@@ -150,20 +150,83 @@ namespace FlaxEditor.Windows
cm.AddButton("New folder", NewFolder); cm.AddButton("New folder", NewFolder);
} }
c = cm.AddChildMenu("New"); // Loop through each proxy and user defined json type and add them to the context menu
c.ContextMenu.Tag = item; var actorType = new ScriptType(typeof(Actor));
c.ContextMenu.AutoSort = true; var scriptType = new ScriptType(typeof(Script));
int newItems = 0; foreach (var type in Editor.CodeEditing.All.Get())
for (int i = 0; i < Editor.ContentDatabase.Proxy.Count; i++)
{ {
var p = Editor.ContentDatabase.Proxy[i]; if (type.IsAbstract)
continue;
if (actorType.IsAssignableFrom(type) || scriptType.IsAssignableFrom(type))
continue;
// Get attribute
ContentContextMenuAttribute attribute = null;
foreach (var typeAttribute in type.GetAttributes(true))
{
if (typeAttribute is ContentContextMenuAttribute contentContextMenuAttribute)
{
attribute = contentContextMenuAttribute;
break;
}
}
if (attribute == null)
continue;
// Get context proxy
ContentProxy p;
if (type.Type.IsSubclassOf(typeof(ContentProxy)))
{
p = Editor.ContentDatabase.Proxy.Find(x => x.GetType() == type.Type);
}
else
{
// User can use attribute to put their own assets into the content context menu
var generic = typeof(SpawnableJsonAssetProxy<>).MakeGenericType(type.Type);
var instance = Activator.CreateInstance(generic);
p = instance as AssetProxy;
}
if (p == null)
continue;
if (p.CanCreate(folder)) if (p.CanCreate(folder))
{ {
c.ContextMenu.AddButton(p.Name, () => NewItem(p)); var parts = attribute.Path.Split('/');
newItems++; ContextMenuChildMenu childCM = null;
bool mainCM = true;
for (int i = 0; i < parts?.Length; i++)
{
var part = parts[i].Trim();
if (i == parts.Length - 1)
{
if (mainCM)
{
cm.AddButton(part, () => NewItem(p));
mainCM = false;
}
else if (childCM != null)
{
childCM.ContextMenu.AddButton(part, () => NewItem(p));
childCM.ContextMenu.AutoSort = true;
}
}
else
{
if (mainCM)
{
childCM = cm.GetOrAddChildMenu(part);
childCM.ContextMenu.AutoSort = true;
mainCM = false;
}
else if (childCM != null)
{
childCM = childCM.ContextMenu.GetOrAddChildMenu(part);
childCM.ContextMenu.AutoSort = true;
}
}
}
} }
} }
c.Enabled = newItems > 0;
if (folder.CanHaveAssets) if (folder.CanHaveAssets)
{ {

View File

@@ -65,7 +65,6 @@ namespace FlaxEditor.Windows
{ {
if (actorType.IsAbstract) if (actorType.IsAbstract)
continue; continue;
ActorContextMenuAttribute attribute = null; ActorContextMenuAttribute attribute = null;
foreach (var e in actorType.GetAttributes(true)) foreach (var e in actorType.GetAttributes(true))
{ {
@@ -77,44 +76,46 @@ namespace FlaxEditor.Windows
} }
if (attribute == null) if (attribute == null)
continue; continue;
var splitPath = attribute?.Path.Split('/'); var parts = attribute.Path.Split('/');
ContextMenuChildMenu childCM = convertMenu; ContextMenuChildMenu childCM = convertMenu;
bool mainCM = true; bool mainCM = true;
for (int i = 0; i < splitPath?.Length; i++) for (int i = 0; i < parts.Length; i++)
{ {
if (i == splitPath.Length - 1) var part = parts[i].Trim();
if (i == parts.Length - 1)
{ {
if (mainCM) if (mainCM)
{ {
convertMenu.ContextMenu.AddButton(splitPath[i].Trim(), () => Editor.SceneEditing.Convert(actorType.Type)); convertMenu.ContextMenu.AddButton(part, () => Editor.SceneEditing.Convert(actorType.Type));
mainCM = false; mainCM = false;
} }
else else
{ {
childCM?.ContextMenu.AddButton(splitPath[i].Trim(), () => Editor.SceneEditing.Convert(actorType.Type)); childCM.ContextMenu.AddButton(part, () => Editor.SceneEditing.Convert(actorType.Type));
childCM.ContextMenu.AutoSort = true; childCM.ContextMenu.AutoSort = true;
} }
} }
else else
{ {
// Remove new path for converting menu // Remove new path for converting menu
if (splitPath[i] == "New") if (parts[i] == "New")
continue; continue;
if (mainCM) if (mainCM)
{ {
childCM = convertMenu.ContextMenu.GetOrAddChildMenu(splitPath[i].Trim()); childCM = convertMenu.ContextMenu.GetOrAddChildMenu(part);
childCM.ContextMenu.AutoSort = true;
mainCM = false; mainCM = false;
} }
else else
{ {
childCM = childCM?.ContextMenu.GetOrAddChildMenu(splitPath[i].Trim()); childCM = childCM.ContextMenu.GetOrAddChildMenu(part);
}
childCM.ContextMenu.AutoSort = true; childCM.ContextMenu.AutoSort = true;
} }
} }
} }
} }
}
b = contextMenu.AddButton("Delete", Editor.SceneEditing.Delete); b = contextMenu.AddButton("Delete", Editor.SceneEditing.Delete);
b.Enabled = hasSthSelected; b.Enabled = hasSthSelected;

View File

@@ -435,6 +435,11 @@ API_ENUM() enum class MaterialSceneTextures
/// The material shading mode. /// The material shading mode.
/// </summary> /// </summary>
ShadingModel = 10, ShadingModel = 10,
/// <summary>
/// The scene world-space position (relative to the render view origin).
/// </summary>
WorldPosition = 11,
}; };
/// <summary> /// <summary>

View File

@@ -439,6 +439,7 @@ void MaterialParameter::Bind(BindMeta& meta) const
switch (type) switch (type)
{ {
case MaterialSceneTextures::SceneDepth: case MaterialSceneTextures::SceneDepth:
case MaterialSceneTextures::WorldPosition:
view = meta.CanSampleDepth view = meta.CanSampleDepth
? meta.Buffers->DepthBuffer->GetDescription().Flags & GPUTextureFlags::ReadOnlyDepthView ? meta.Buffers->DepthBuffer->GetDescription().Flags & GPUTextureFlags::ReadOnlyDepthView
? meta.Buffers->DepthBuffer->ViewReadOnlyDepth() ? meta.Buffers->DepthBuffer->ViewReadOnlyDepth()

View File

@@ -18,6 +18,7 @@ PACK_STRUCT(struct PostFxMaterialShaderData {
Float4 ViewInfo; Float4 ViewInfo;
Float4 ScreenSize; Float4 ScreenSize;
Float4 TemporalAAJitter; Float4 TemporalAAJitter;
Matrix InverseViewProjectionMatrix;
}); });
void PostFxMaterialShader::Bind(BindParameters& params) void PostFxMaterialShader::Bind(BindParameters& params)
@@ -44,6 +45,7 @@ void PostFxMaterialShader::Bind(BindParameters& params)
// Setup material constants // Setup material constants
{ {
Matrix::Transpose(view.View, materialData->ViewMatrix); Matrix::Transpose(view.View, materialData->ViewMatrix);
Matrix::Transpose(view.IVP, materialData->InverseViewProjectionMatrix);
materialData->ViewPos = view.Position; materialData->ViewPos = view.Position;
materialData->ViewFar = view.Far; materialData->ViewFar = view.Far;
materialData->ViewDir = view.Direction; materialData->ViewDir = view.Direction;

View File

@@ -113,6 +113,11 @@ bool ShaderAssetBase::Save()
bool IsValidShaderCache(DataContainer<byte>& shaderCache, Array<String>& includes) bool IsValidShaderCache(DataContainer<byte>& shaderCache, Array<String>& includes)
{ {
if (shaderCache.Length() == 0)
{
return false;
}
MemoryReadStream stream(shaderCache.Get(), shaderCache.Length()); MemoryReadStream stream(shaderCache.Get(), shaderCache.Length());
// Read cache format version // Read cache format version

View File

@@ -245,6 +245,9 @@ void ParticleEmitterGPUGenerator::ProcessGroupTextures(Box* box, Node* node, Val
value = writeLocal(VariantType::Int, String::Format(TEXT("(int)({0}.a * 3.999)"), gBuffer1Sample.Value), node); value = writeLocal(VariantType::Int, String::Format(TEXT("(int)({0}.a * 3.999)"), gBuffer1Sample.Value), node);
break; break;
} }
case MaterialSceneTextures::WorldPosition:
value = Value::Zero; // Not implemented
break;
default: default:
{ {
// Sample single texture // Sample single texture

View File

@@ -8,7 +8,7 @@
/// <summary> /// <summary>
/// Physical materials are used to define the response of a physical object when interacting dynamically with the world. /// Physical materials are used to define the response of a physical object when interacting dynamically with the world.
/// </summary> /// </summary>
API_CLASS() class FLAXENGINE_API PhysicalMaterial final : public ISerializable API_CLASS(Attributes = "ContentContextMenu(\"New/Physics/Physical Material\")") class FLAXENGINE_API PhysicalMaterial final : public ISerializable
{ {
API_AUTO_SERIALIZATION(); API_AUTO_SERIALIZATION();
DECLARE_SCRIPTING_TYPE_MINIMAL(PhysicalMaterial); DECLARE_SCRIPTING_TYPE_MINIMAL(PhysicalMaterial);

View File

@@ -0,0 +1,26 @@
using System;
namespace FlaxEngine
{
/// <summary>
/// This attribute is used to show content items that can be created in the content browser context menu. Separate the subcontext menus with a /.
/// </summary>
[Serializable]
[AttributeUsage(AttributeTargets.Class)]
public class ContentContextMenuAttribute : Attribute
{
/// <summary>
/// The path to be used in the context menu
/// </summary>
public string Path;
/// <summary>
/// Initializes a new instance of the <see cref="ContentContextMenuAttribute"/> class.
/// </summary>
/// <param name="path">The path to use to create the context menu</param>
public ContentContextMenuAttribute(string path)
{
Path = path;
}
}
}

View File

@@ -1,166 +0,0 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#if COMPILE_WITH_MATERIAL_GRAPH
#include "MaterialGenerator.h"
MaterialValue* MaterialGenerator::sampleTextureRaw(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture)
{
ASSERT(texture && box);
// Cache data
const auto parent = box->GetParent<ShaderGraphNode<>>();
const bool isCubemap = texture->Type == MaterialParameterType::CubeTexture;
const bool isArray = texture->Type == MaterialParameterType::GPUTextureArray;
const bool isVolume = texture->Type == MaterialParameterType::GPUTextureVolume;
const bool isNormalMap = texture->Type == MaterialParameterType::NormalMap;
const bool canUseSample = CanUseSample(_treeType);
MaterialGraphBox* valueBox = parent->GetBox(1);
// Check if has variable assigned
if (texture->Type != MaterialParameterType::Texture
&& texture->Type != MaterialParameterType::NormalMap
&& texture->Type != MaterialParameterType::SceneTexture
&& texture->Type != MaterialParameterType::GPUTexture
&& texture->Type != MaterialParameterType::GPUTextureVolume
&& texture->Type != MaterialParameterType::GPUTextureCube
&& texture->Type != MaterialParameterType::GPUTextureArray
&& texture->Type != MaterialParameterType::CubeTexture)
{
OnError(caller, box, TEXT("No parameter for texture sample node."));
return nullptr;
}
// Check if it's 'Object' box that is using only texture object without sampling
if (box->ID == 6)
{
// Return texture object
value.Value = texture->ShaderName;
value.Type = VariantType::Object;
return nullptr;
}
// Check if hasn't been sampled during that tree eating
if (valueBox->Cache.IsInvalid())
{
// Check if use custom UVs
String uv;
MaterialGraphBox* uvBox = parent->GetBox(0);
bool useCustomUVs = uvBox->HasConnection();
bool use3dUVs = isCubemap || isArray || isVolume;
if (useCustomUVs)
{
// Get custom UVs
auto textureParamId = texture->ID;
ASSERT(textureParamId.IsValid());
MaterialValue v = tryGetValue(uvBox, getUVs);
uv = MaterialValue::Cast(v, use3dUVs ? VariantType::Float3 : VariantType::Float2).Value;
// Restore texture (during tryGetValue pointer could go invalid)
texture = findParam(textureParamId);
ASSERT(texture);
}
else
{
// Use default UVs
uv = use3dUVs ? TEXT("float3(input.TexCoord.xy, 0)") : TEXT("input.TexCoord.xy");
}
// Select sampler
// TODO: add option for texture groups and per texture options like wrap mode etc.
// TODO: changing texture sampler option
const Char* sampler = TEXT("SamplerLinearWrap");
// Sample texture
if (isNormalMap)
{
const Char* format = canUseSample ? TEXT("{0}.Sample({1}, {2}).xyz") : TEXT("{0}.SampleLevel({1}, {2}, 0).xyz");
// Sample encoded normal map
const String sampledValue = String::Format(format, texture->ShaderName, sampler, uv);
const auto normalVector = writeLocal(VariantType::Float3, sampledValue, parent);
// Decode normal vector
_writer.Write(TEXT("\t{0}.xy = {0}.xy * 2.0 - 1.0;\n"), normalVector.Value);
_writer.Write(TEXT("\t{0}.z = sqrt(saturate(1.0 - dot({0}.xy, {0}.xy)));\n"), normalVector.Value);
valueBox->Cache = normalVector;
}
else
{
// Select format string based on texture type
const Char* format;
/*if (isCubemap)
{
MISSING_CODE("sampling cube maps and 3d texture in material generator");
//format = TEXT("SAMPLE_CUBEMAP({0}, {1})");
}
else*/
{
/*if (useCustomUVs)
{
createGradients(writer, parent);
format = TEXT("SAMPLE_TEXTURE_GRAD({0}, {1}, {2}, {3})");
}
else*/
{
format = canUseSample ? TEXT("{0}.Sample({1}, {2})") : TEXT("{0}.SampleLevel({1}, {2}, 0)");
}
}
// Sample texture
String sampledValue = String::Format(format, texture->ShaderName, sampler, uv, _ddx.Value, _ddy.Value);
valueBox->Cache = writeLocal(VariantType::Float4, sampledValue, parent);
}
}
return &valueBox->Cache;
}
void MaterialGenerator::sampleTexture(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture)
{
const auto sample = sampleTextureRaw(caller, value, box, texture);
if (sample == nullptr)
return;
// Set result values based on box ID
switch (box->ID)
{
case 1:
value = *sample;
break;
case 2:
value.Value = sample->Value + _subs[0];
break;
case 3:
value.Value = sample->Value + _subs[1];
break;
case 4:
value.Value = sample->Value + _subs[2];
break;
case 5:
value.Value = sample->Value + _subs[3];
break;
default: CRASH;
break;
}
value.Type = box->Type.Type;
}
void MaterialGenerator::sampleSceneDepth(Node* caller, Value& value, Box* box)
{
// Sample depth buffer
auto param = findOrAddSceneTexture(MaterialSceneTextures::SceneDepth);
const auto depthSample = sampleTextureRaw(caller, value, box, &param);
if (depthSample == nullptr)
return;
// Linearize raw device depth
linearizeSceneDepth(caller, *depthSample, value);
}
void MaterialGenerator::linearizeSceneDepth(Node* caller, const Value& depth, Value& value)
{
value = writeLocal(VariantType::Float, String::Format(TEXT("ViewInfo.w / ({0}.x - ViewInfo.z)"), depth.Value), caller);
}
#endif

View File

@@ -4,6 +4,165 @@
#include "MaterialGenerator.h" #include "MaterialGenerator.h"
MaterialValue* MaterialGenerator::sampleTextureRaw(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture)
{
ASSERT(texture && box);
// Cache data
const auto parent = box->GetParent<ShaderGraphNode<>>();
const bool isCubemap = texture->Type == MaterialParameterType::CubeTexture;
const bool isArray = texture->Type == MaterialParameterType::GPUTextureArray;
const bool isVolume = texture->Type == MaterialParameterType::GPUTextureVolume;
const bool isNormalMap = texture->Type == MaterialParameterType::NormalMap;
const bool canUseSample = CanUseSample(_treeType);
MaterialGraphBox* valueBox = parent->GetBox(1);
// Check if has variable assigned
if (texture->Type != MaterialParameterType::Texture
&& texture->Type != MaterialParameterType::NormalMap
&& texture->Type != MaterialParameterType::SceneTexture
&& texture->Type != MaterialParameterType::GPUTexture
&& texture->Type != MaterialParameterType::GPUTextureVolume
&& texture->Type != MaterialParameterType::GPUTextureCube
&& texture->Type != MaterialParameterType::GPUTextureArray
&& texture->Type != MaterialParameterType::CubeTexture)
{
OnError(caller, box, TEXT("No parameter for texture sample node."));
return nullptr;
}
// Check if it's 'Object' box that is using only texture object without sampling
if (box->ID == 6)
{
// Return texture object
value.Value = texture->ShaderName;
value.Type = VariantType::Object;
return nullptr;
}
// Check if hasn't been sampled during that tree eating
if (valueBox->Cache.IsInvalid())
{
// Check if use custom UVs
String uv;
MaterialGraphBox* uvBox = parent->GetBox(0);
bool useCustomUVs = uvBox->HasConnection();
bool use3dUVs = isCubemap || isArray || isVolume;
if (useCustomUVs)
{
// Get custom UVs
auto textureParamId = texture->ID;
ASSERT(textureParamId.IsValid());
MaterialValue v = tryGetValue(uvBox, getUVs);
uv = MaterialValue::Cast(v, use3dUVs ? VariantType::Float3 : VariantType::Float2).Value;
// Restore texture (during tryGetValue pointer could go invalid)
texture = findParam(textureParamId);
ASSERT(texture);
}
else
{
// Use default UVs
uv = use3dUVs ? TEXT("float3(input.TexCoord.xy, 0)") : TEXT("input.TexCoord.xy");
}
// Select sampler
// TODO: add option for texture groups and per texture options like wrap mode etc.
// TODO: changing texture sampler option
const Char* sampler = TEXT("SamplerLinearWrap");
// Sample texture
if (isNormalMap)
{
const Char* format = canUseSample ? TEXT("{0}.Sample({1}, {2}).xyz") : TEXT("{0}.SampleLevel({1}, {2}, 0).xyz");
// Sample encoded normal map
const String sampledValue = String::Format(format, texture->ShaderName, sampler, uv);
const auto normalVector = writeLocal(VariantType::Float3, sampledValue, parent);
// Decode normal vector
_writer.Write(TEXT("\t{0}.xy = {0}.xy * 2.0 - 1.0;\n"), normalVector.Value);
_writer.Write(TEXT("\t{0}.z = sqrt(saturate(1.0 - dot({0}.xy, {0}.xy)));\n"), normalVector.Value);
valueBox->Cache = normalVector;
}
else
{
// Select format string based on texture type
const Char* format;
/*if (isCubemap)
{
MISSING_CODE("sampling cube maps and 3d texture in material generator");
//format = TEXT("SAMPLE_CUBEMAP({0}, {1})");
}
else*/
{
/*if (useCustomUVs)
{
createGradients(writer, parent);
format = TEXT("SAMPLE_TEXTURE_GRAD({0}, {1}, {2}, {3})");
}
else*/
{
format = canUseSample ? TEXT("{0}.Sample({1}, {2})") : TEXT("{0}.SampleLevel({1}, {2}, 0)");
}
}
// Sample texture
String sampledValue = String::Format(format, texture->ShaderName, sampler, uv, _ddx.Value, _ddy.Value);
valueBox->Cache = writeLocal(VariantType::Float4, sampledValue, parent);
}
}
return &valueBox->Cache;
}
void MaterialGenerator::sampleTexture(Node* caller, Value& value, Box* box, SerializedMaterialParam* texture)
{
const auto sample = sampleTextureRaw(caller, value, box, texture);
if (sample == nullptr)
return;
// Set result values based on box ID
switch (box->ID)
{
case 1:
value = *sample;
break;
case 2:
value.Value = sample->Value + _subs[0];
break;
case 3:
value.Value = sample->Value + _subs[1];
break;
case 4:
value.Value = sample->Value + _subs[2];
break;
case 5:
value.Value = sample->Value + _subs[3];
break;
default: CRASH;
break;
}
value.Type = box->Type.Type;
}
void MaterialGenerator::sampleSceneDepth(Node* caller, Value& value, Box* box)
{
// Sample depth buffer
auto param = findOrAddSceneTexture(MaterialSceneTextures::SceneDepth);
const auto depthSample = sampleTextureRaw(caller, value, box, &param);
if (depthSample == nullptr)
return;
// Linearize raw device depth
linearizeSceneDepth(caller, *depthSample, value);
}
void MaterialGenerator::linearizeSceneDepth(Node* caller, const Value& depth, Value& value)
{
value = writeLocal(VariantType::Float, String::Format(TEXT("ViewInfo.w / ({0}.x - ViewInfo.z)"), depth.Value), caller);
}
void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value) void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
{ {
switch (node->TypeID) switch (node->TypeID)
@@ -257,6 +416,23 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
value = writeLocal(VariantType::Int, String::Format(TEXT("(int)({0}.a * 3.999)"), gBuffer1Sample->Value), node); value = writeLocal(VariantType::Int, String::Format(TEXT("(int)({0}.a * 3.999)"), gBuffer1Sample->Value), node);
break; break;
} }
case MaterialSceneTextures::WorldPosition:
{
auto depthParam = findOrAddSceneTexture(MaterialSceneTextures::SceneDepth);
auto depthSample = sampleTextureRaw(node, value, box, &depthParam);
if (depthSample == nullptr)
break;
const auto parent = box->GetParent<ShaderGraphNode<>>();
MaterialGraphBox* uvBox = parent->GetBox(0);
bool useCustomUVs = uvBox->HasConnection();
String uv;
if (useCustomUVs)
uv = MaterialValue::Cast(tryGetValue(uvBox, getUVs), VariantType::Float2).Value;
else
uv = TEXT("input.TexCoord.xy");
value = writeLocal(VariantType::Float3, String::Format(TEXT("GetWorldPos({1}, {0}.rgb)"), depthSample->Value, uv), node);
break;
}
default: default:
{ {
// Sample single texture // Sample single texture

View File

@@ -229,6 +229,11 @@ namespace FlaxEngine.GUI
[EditorOrder(529)] [EditorOrder(529)]
public bool ClipText { get; set; } = true; public bool ClipText { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating whether you can scroll the text in the text box (eg. with a mouse wheel).
/// </summary>
public bool IsMultilineScrollable { get; set; } = true;
/// <summary> /// <summary>
/// Gets or sets textbox background color when the control is selected (has focus). /// Gets or sets textbox background color when the control is selected (has focus).
/// </summary> /// </summary>
@@ -1157,7 +1162,7 @@ namespace FlaxEngine.GUI
return true; return true;
// Multiline scroll // Multiline scroll
if (IsMultiline && _text.Length != 0) if (IsMultiline && _text.Length != 0 && IsMultilineScrollable)
{ {
TargetViewOffset = Float2.Clamp(_targetViewOffset - new Float2(0, delta * 10.0f), Float2.Zero, new Float2(_targetViewOffset.X, _textSize.Y)); TargetViewOffset = Float2.Clamp(_targetViewOffset - new Float2(0, delta * 10.0f), Float2.Zero, new Float2(_targetViewOffset.X, _textSize.Y));
return true; return true;