Merge remote-tracking branch 'origin/master' into 1.13
# Conflicts: # Source/Editor/SceneGraph/GUI/ActorTreeNode.cs # Source/Engine/Graphics/Graphics.h # Source/Engine/Renderer/ShadowsPass.cpp
This commit is contained in:
@@ -343,6 +343,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool _buildOnUpdate;
|
private bool _buildOnUpdate;
|
||||||
|
private bool _initialized;
|
||||||
private bool _readOnly;
|
private bool _readOnly;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -430,6 +431,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
|
|
||||||
ClearLayout();
|
ClearLayout();
|
||||||
_buildOnUpdate = false;
|
_buildOnUpdate = false;
|
||||||
|
_initialized = true;
|
||||||
Editor.Setup(this);
|
Editor.Setup(this);
|
||||||
|
|
||||||
Panel.IsLayoutLocked = false;
|
Panel.IsLayoutLocked = false;
|
||||||
@@ -506,7 +508,11 @@ namespace FlaxEditor.CustomEditors
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnSelectionChanged()
|
protected virtual void OnSelectionChanged()
|
||||||
{
|
{
|
||||||
BuildLayout();
|
// Defer building the layout after we have initialized to improve initial loading times
|
||||||
|
if (!_initialized)
|
||||||
|
_buildOnUpdate = true;
|
||||||
|
else
|
||||||
|
BuildLayout();
|
||||||
SelectionChanged?.Invoke();
|
SelectionChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
if (_previouslyFocused != null)
|
if (_previouslyFocused != null)
|
||||||
{
|
{
|
||||||
_previouslyFocused.RootWindow?.Focus();
|
_previouslyFocused.RootWindow?.Focus();
|
||||||
_previouslyFocused.Focus();
|
_previouslyFocused?.Focus();
|
||||||
_previouslyFocused = null;
|
_previouslyFocused = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -222,7 +222,10 @@ internal class DirectionGizmo : ContainerControl
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This could be some actual math expression, not that hack
|
// This could be some actual math expression, not that hack
|
||||||
var fov = _owner.Viewport.FieldOfView / 60.0f;
|
float fov = _owner.Viewport.FieldOfView;
|
||||||
|
if (_owner.Viewport.ViewportCamera is Viewport.Cameras.FPSCamera fpsCam)
|
||||||
|
fov += fpsCam.AdditionalZoomFOV;
|
||||||
|
fov /= 60.0f;
|
||||||
float scaleAt30 = 0.1f, scaleAt60 = 1.0f, scaleAt120 = 1.5f, scaleAt180 = 3.0f;
|
float scaleAt30 = 0.1f, scaleAt60 = 1.0f, scaleAt120 = 1.5f, scaleAt180 = 3.0f;
|
||||||
heightNormalization /= Mathf.Lerp(scaleAt30, scaleAt60, fov);
|
heightNormalization /= Mathf.Lerp(scaleAt30, scaleAt60, fov);
|
||||||
heightNormalization /= Mathf.Lerp(scaleAt60, scaleAt120, Mathf.Saturate(fov - 1));
|
heightNormalization /= Mathf.Lerp(scaleAt60, scaleAt120, Mathf.Saturate(fov - 1));
|
||||||
|
|||||||
@@ -2,12 +2,8 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Xml;
|
|
||||||
using FlaxEditor.Scripting;
|
using FlaxEditor.Scripting;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
|
||||||
@@ -21,7 +17,6 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
|||||||
{
|
{
|
||||||
private Dictionary<ScriptType, string> _typeCache = new Dictionary<ScriptType, string>();
|
private Dictionary<ScriptType, string> _typeCache = new Dictionary<ScriptType, string>();
|
||||||
private Dictionary<ScriptMemberInfo, string> _memberCache = new Dictionary<ScriptMemberInfo, string>();
|
private Dictionary<ScriptMemberInfo, string> _memberCache = new Dictionary<ScriptMemberInfo, string>();
|
||||||
private Dictionary<Assembly, Dictionary<string, string>> _xmlCache = new Dictionary<Assembly, Dictionary<string, string>>();
|
|
||||||
|
|
||||||
internal CodeDocsModule(Editor editor)
|
internal CodeDocsModule(Editor editor)
|
||||||
: base(editor)
|
: base(editor)
|
||||||
@@ -61,13 +56,9 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
|||||||
else if (type.Type != null)
|
else if (type.Type != null)
|
||||||
{
|
{
|
||||||
// Try to use xml docs for managed type
|
// Try to use xml docs for managed type
|
||||||
var xml = GetXmlDocs(type.Type.Assembly);
|
var xmlDoc = DebugCommands.GetXml(type.Type);
|
||||||
if (xml != null)
|
if (xmlDoc != null)
|
||||||
{
|
text += '\n' + xmlDoc;
|
||||||
var key = "T:" + GetXmlKey(type.Type.FullName);
|
|
||||||
if (xml.TryGetValue(key, out var xmlDoc))
|
|
||||||
text += '\n' + FilterWhitespaces(xmlDoc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_typeCache.Add(type, text);
|
_typeCache.Add(type, text);
|
||||||
@@ -108,242 +99,20 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
|||||||
else if (member.Type != null)
|
else if (member.Type != null)
|
||||||
{
|
{
|
||||||
// Try to use xml docs for managed member
|
// Try to use xml docs for managed member
|
||||||
var memberInfo = member.Type;
|
var xmlDoc = DebugCommands.GetXml(member.Type);
|
||||||
var xml = GetXmlDocs(memberInfo.DeclaringType.Assembly);
|
if (xmlDoc != null)
|
||||||
if (xml != null)
|
text = xmlDoc;
|
||||||
{
|
|
||||||
// [Reference: MSDN Magazine, October 2019, Volume 34 Number 10, "Accessing XML Documentation via Reflection"]
|
|
||||||
// https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/october/csharp-accessing-xml-documentation-via-reflection
|
|
||||||
var memberType = memberInfo.MemberType;
|
|
||||||
string key = null;
|
|
||||||
if (memberType.HasFlag(MemberTypes.Field))
|
|
||||||
{
|
|
||||||
var fieldInfo = (FieldInfo)memberInfo;
|
|
||||||
key = "F:" + GetXmlKey(fieldInfo.DeclaringType.FullName) + "." + fieldInfo.Name;
|
|
||||||
}
|
|
||||||
else if (memberType.HasFlag(MemberTypes.Property))
|
|
||||||
{
|
|
||||||
var propertyInfo = (PropertyInfo)memberInfo;
|
|
||||||
key = "P:" + GetXmlKey(propertyInfo.DeclaringType.FullName) + "." + propertyInfo.Name;
|
|
||||||
}
|
|
||||||
else if (memberType.HasFlag(MemberTypes.Event))
|
|
||||||
{
|
|
||||||
var eventInfo = (EventInfo)memberInfo;
|
|
||||||
key = "E:" + GetXmlKey(eventInfo.DeclaringType.FullName) + "." + eventInfo.Name;
|
|
||||||
}
|
|
||||||
else if (memberType.HasFlag(MemberTypes.Constructor))
|
|
||||||
{
|
|
||||||
var constructorInfo = (ConstructorInfo)memberInfo;
|
|
||||||
key = GetXmlKey(constructorInfo);
|
|
||||||
}
|
|
||||||
else if (memberType.HasFlag(MemberTypes.Method))
|
|
||||||
{
|
|
||||||
var methodInfo = (MethodInfo)memberInfo;
|
|
||||||
key = GetXmlKey(methodInfo);
|
|
||||||
}
|
|
||||||
else if (memberType.HasFlag(MemberTypes.TypeInfo) || memberType.HasFlag(MemberTypes.NestedType))
|
|
||||||
{
|
|
||||||
var typeInfo = (TypeInfo)memberInfo;
|
|
||||||
key = "T:" + GetXmlKey(typeInfo.FullName);
|
|
||||||
}
|
|
||||||
if (key != null)
|
|
||||||
xml.TryGetValue(key, out text);
|
|
||||||
|
|
||||||
// Customize tooltips for properties to be more human-readable in UI
|
|
||||||
if (text != null && memberType.HasFlag(MemberTypes.Property) && text.StartsWith("Gets or sets ", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
text = text.Substring(13);
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (char* e = text)
|
|
||||||
e[0] = char.ToUpper(e[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_memberCache.Add(member, text);
|
_memberCache.Add(member, text);
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
// [Reference: MSDN Magazine, October 2019, Volume 34 Number 10, "Accessing XML Documentation via Reflection"]
|
|
||||||
// https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/october/csharp-accessing-xml-documentation-via-reflection
|
|
||||||
|
|
||||||
private string GetXmlKey(MethodInfo methodInfo)
|
|
||||||
{
|
|
||||||
var typeGenericMap = new Dictionary<string, int>();
|
|
||||||
var methodGenericMap = new Dictionary<string, int>();
|
|
||||||
ParameterInfo[] parameterInfos = methodInfo.GetParameters();
|
|
||||||
|
|
||||||
if (methodInfo.DeclaringType.IsGenericType)
|
|
||||||
{
|
|
||||||
var methods = methodInfo.DeclaringType.GetGenericTypeDefinition().GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
|
|
||||||
methodInfo = methods.First(x => x.MetadataToken == methodInfo.MetadataToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
Type[] typeGenericArguments = methodInfo.DeclaringType.GetGenericArguments();
|
|
||||||
for (int i = 0; i < typeGenericArguments.Length; i++)
|
|
||||||
{
|
|
||||||
Type typeGeneric = typeGenericArguments[i];
|
|
||||||
typeGenericMap[typeGeneric.Name] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type[] methodGenericArguments = methodInfo.GetGenericArguments();
|
|
||||||
for (int i = 0; i < methodGenericArguments.Length; i++)
|
|
||||||
{
|
|
||||||
Type methodGeneric = methodGenericArguments[i];
|
|
||||||
methodGenericMap[methodGeneric.Name] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
string declarationTypeString = GetXmlKey(methodInfo.DeclaringType, false, typeGenericMap, methodGenericMap);
|
|
||||||
string memberNameString = methodInfo.Name;
|
|
||||||
string methodGenericArgumentsString = methodGenericMap.Count > 0 ? "``" + methodGenericMap.Count : string.Empty;
|
|
||||||
string parametersString = parameterInfos.Length > 0 ? "(" + string.Join(",", methodInfo.GetParameters().Select(x => GetXmlKey(x.ParameterType, true, typeGenericMap, methodGenericMap))) + ")" : string.Empty;
|
|
||||||
|
|
||||||
string key = "M:" + declarationTypeString + "." + memberNameString + methodGenericArgumentsString + parametersString;
|
|
||||||
if (methodInfo.Name is "op_Implicit" || methodInfo.Name is "op_Explicit")
|
|
||||||
{
|
|
||||||
key += "~" + GetXmlKey(methodInfo.ReturnType, true, typeGenericMap, methodGenericMap);
|
|
||||||
}
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetXmlKey(ConstructorInfo constructorInfo)
|
|
||||||
{
|
|
||||||
var typeGenericMap = new Dictionary<string, int>();
|
|
||||||
var methodGenericMap = new Dictionary<string, int>();
|
|
||||||
ParameterInfo[] parameterInfos = constructorInfo.GetParameters();
|
|
||||||
|
|
||||||
Type[] typeGenericArguments = constructorInfo.DeclaringType.GetGenericArguments();
|
|
||||||
for (int i = 0; i < typeGenericArguments.Length; i++)
|
|
||||||
{
|
|
||||||
Type typeGeneric = typeGenericArguments[i];
|
|
||||||
typeGenericMap[typeGeneric.Name] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
string declarationTypeString = GetXmlKey(constructorInfo.DeclaringType, false, typeGenericMap, methodGenericMap);
|
|
||||||
string methodGenericArgumentsString = methodGenericMap.Count > 0 ? "``" + methodGenericMap.Count : string.Empty;
|
|
||||||
string parametersString = parameterInfos.Length > 0 ? "(" + string.Join(",", constructorInfo.GetParameters().Select(x => GetXmlKey(x.ParameterType, true, typeGenericMap, methodGenericMap))) + ")" : string.Empty;
|
|
||||||
|
|
||||||
return "M:" + declarationTypeString + "." + "#ctor" + methodGenericArgumentsString + parametersString;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string GetXmlKey(Type type, bool isMethodParameter, Dictionary<string, int> typeGenericMap, Dictionary<string, int> methodGenericMap)
|
|
||||||
{
|
|
||||||
if (type.IsGenericParameter)
|
|
||||||
{
|
|
||||||
if (methodGenericMap.TryGetValue(type.Name, out var methodIndex))
|
|
||||||
return "``" + methodIndex;
|
|
||||||
if (typeGenericMap.TryGetValue(type.Name, out var typeKey))
|
|
||||||
return "`" + typeKey;
|
|
||||||
return "`";
|
|
||||||
}
|
|
||||||
if (type.HasElementType)
|
|
||||||
{
|
|
||||||
string elementTypeString = GetXmlKey(type.GetElementType(), isMethodParameter, typeGenericMap, methodGenericMap);
|
|
||||||
if (type.IsPointer)
|
|
||||||
return elementTypeString + "*";
|
|
||||||
if (type.IsByRef)
|
|
||||||
return elementTypeString + "@";
|
|
||||||
if (type.IsArray)
|
|
||||||
{
|
|
||||||
int rank = type.GetArrayRank();
|
|
||||||
string arrayDimensionsString = rank > 1 ? "[" + string.Join(",", Enumerable.Repeat("0:", rank)) + "]" : "[]";
|
|
||||||
return elementTypeString + arrayDimensionsString;
|
|
||||||
}
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
string prefaceString = type.IsNested ? GetXmlKey(type.DeclaringType, isMethodParameter, typeGenericMap, methodGenericMap) + "." : type.Namespace + ".";
|
|
||||||
string typeNameString = isMethodParameter ? Regex.Replace(type.Name, @"`\d+", string.Empty) : type.Name;
|
|
||||||
string genericArgumentsString = type.IsGenericType && isMethodParameter ? "{" + string.Join(",", type.GetGenericArguments().Select(argument => GetXmlKey(argument, true, typeGenericMap, methodGenericMap))) + "}" : string.Empty;
|
|
||||||
return prefaceString + typeNameString + genericArgumentsString;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetXmlKey(string typeFullNameString)
|
|
||||||
{
|
|
||||||
return Regex.Replace(typeFullNameString, @"\[.*\]", string.Empty).Replace('+', '.');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string FilterWhitespaces(string str)
|
|
||||||
{
|
|
||||||
if (str.Contains(" ", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
var prev = str[0];
|
|
||||||
sb.Append(prev);
|
|
||||||
for (int i = 1; i < str.Length; i++)
|
|
||||||
{
|
|
||||||
var c = str[i];
|
|
||||||
if (prev != ' ' || c != ' ')
|
|
||||||
{
|
|
||||||
sb.Append(c);
|
|
||||||
}
|
|
||||||
prev = c;
|
|
||||||
}
|
|
||||||
str = sb.ToString();
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<string, string> GetXmlDocs(Assembly assembly)
|
|
||||||
{
|
|
||||||
if (!_xmlCache.TryGetValue(assembly, out var result))
|
|
||||||
{
|
|
||||||
Profiler.BeginEvent("GetXmlDocs");
|
|
||||||
|
|
||||||
var assemblyPath = Utils.GetAssemblyLocation(assembly);
|
|
||||||
var assemblyName = assembly.GetName().Name;
|
|
||||||
var xmlFilePath = Path.ChangeExtension(assemblyPath, ".xml");
|
|
||||||
if (!File.Exists(assemblyPath) && !string.IsNullOrEmpty(assemblyPath))
|
|
||||||
{
|
|
||||||
var uri = new UriBuilder(assemblyPath);
|
|
||||||
var path = Uri.UnescapeDataString(uri.Path);
|
|
||||||
xmlFilePath = Path.Combine(Path.GetDirectoryName(path), assemblyName + ".xml");
|
|
||||||
}
|
|
||||||
if (File.Exists(xmlFilePath))
|
|
||||||
{
|
|
||||||
Profiler.BeginEvent(assemblyName);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Parse xml documentation
|
|
||||||
using (var xmlReader = XmlReader.Create(new StreamReader(xmlFilePath)))
|
|
||||||
{
|
|
||||||
result = new Dictionary<string, string>();
|
|
||||||
while (xmlReader.Read())
|
|
||||||
{
|
|
||||||
if (xmlReader.NodeType == XmlNodeType.Element && string.Equals(xmlReader.Name, "member", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
string rawName = xmlReader["name"];
|
|
||||||
var memberReader = xmlReader.ReadSubtree();
|
|
||||||
if (memberReader.ReadToDescendant("summary"))
|
|
||||||
{
|
|
||||||
// Remove <see cref=""/> and replace them with the captured group (the content of the cref). Additionally, getting rid of prefixes
|
|
||||||
const string crefPattern = @"<see\s+cref=""(?:[A-Z]:FlaxEngine\.)?([^""]+)""\s*\/>";
|
|
||||||
result[rawName] = Regex.Replace(memberReader.ReadInnerXml(), crefPattern, "$1").Replace('\n', ' ').Trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Ignore errors
|
|
||||||
}
|
|
||||||
Profiler.EndEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
_xmlCache[assembly] = result;
|
|
||||||
Profiler.EndEvent();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTypesCleared()
|
private void OnTypesCleared()
|
||||||
{
|
{
|
||||||
_typeCache.Clear();
|
_typeCache.Clear();
|
||||||
_memberCache.Clear();
|
_memberCache.Clear();
|
||||||
_xmlCache.Clear();
|
DebugCommands.ClearXml();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -347,6 +347,14 @@ namespace FlaxEditor.Options
|
|||||||
[EditorDisplay("Viewport"), EditorOrder(1550)]
|
[EditorDisplay("Viewport"), EditorOrder(1550)]
|
||||||
public InputBinding Down = new InputBinding(KeyboardKeys.Q);
|
public InputBinding Down = new InputBinding(KeyboardKeys.Q);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "C")]
|
||||||
|
[EditorDisplay("Viewport"), EditorOrder(1551)]
|
||||||
|
public InputBinding ZoomIn = new InputBinding(KeyboardKeys.C);
|
||||||
|
|
||||||
|
[DefaultValue(typeof(InputBinding), "Z")]
|
||||||
|
[EditorDisplay("Viewport"), EditorOrder(1552)]
|
||||||
|
public InputBinding ZoomOut = new InputBinding(KeyboardKeys.Z);
|
||||||
|
|
||||||
[DefaultValue(typeof(InputBinding), "None")]
|
[DefaultValue(typeof(InputBinding), "None")]
|
||||||
[EditorDisplay("Viewport", "Toggle Camera Rotation"), EditorOrder(1560)]
|
[EditorDisplay("Viewport", "Toggle Camera Rotation"), EditorOrder(1560)]
|
||||||
public InputBinding CameraToggleRotation = new InputBinding(KeyboardKeys.None);
|
public InputBinding CameraToggleRotation = new InputBinding(KeyboardKeys.None);
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ namespace FlaxEditor.SceneGraph.GUI
|
|||||||
_highlights?.Clear();
|
_highlights?.Clear();
|
||||||
isThisVisible = true;
|
isThisVisible = true;
|
||||||
}
|
}
|
||||||
else if (filterText.Contains(','))
|
else if (filterText.Contains(':'))
|
||||||
{
|
{
|
||||||
var splitFilter = filterText.Split(',');
|
var splitFilter = filterText.Split(',');
|
||||||
var hasAllFilters = true;
|
var hasAllFilters = true;
|
||||||
|
|||||||
@@ -807,8 +807,8 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
},
|
},
|
||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
NodeElementArchetype.Factory.Input(0, "A", true, null, 0),
|
NodeElementArchetype.Factory.Input(0, "UV", true, null, 0),
|
||||||
NodeElementArchetype.Factory.Input(1, "B", true, null, 1),
|
NodeElementArchetype.Factory.Input(1, "Center", true, null, 1),
|
||||||
NodeElementArchetype.Factory.Input(2, "Radius", true, typeof(float), 2, 0),
|
NodeElementArchetype.Factory.Input(2, "Radius", true, typeof(float), 2, 0),
|
||||||
NodeElementArchetype.Factory.Input(3, "Hardness", true, typeof(float), 3, 1),
|
NodeElementArchetype.Factory.Input(3, "Hardness", true, typeof(float), 3, 1),
|
||||||
NodeElementArchetype.Factory.Input(4, "Invert", true, typeof(bool), 4, 2),
|
NodeElementArchetype.Factory.Input(4, "Invert", true, typeof(bool), 4, 2),
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace FlaxEditor.Viewport.Cameras
|
|||||||
private Transform _startMove;
|
private Transform _startMove;
|
||||||
private Transform _endMove;
|
private Transform _endMove;
|
||||||
private float _moveStartTime = -1;
|
private float _moveStartTime = -1;
|
||||||
|
private float _additionalFOV;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this viewport is animating movement.
|
/// Gets a value indicating whether this viewport is animating movement.
|
||||||
@@ -32,6 +33,15 @@ namespace FlaxEditor.Viewport.Cameras
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Vector3 TargetPoint = new Vector3(-200);
|
public Vector3 TargetPoint = new Vector3(-200);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Additional field of view used for zooming the camera in and out.
|
||||||
|
/// </summary>
|
||||||
|
public float AdditionalZoomFOV
|
||||||
|
{
|
||||||
|
get => _additionalFOV;
|
||||||
|
private set => _additionalFOV = Mathf.Clamp(value, 5 - Viewport.FieldOfView, 160f - Viewport.FieldOfView);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets view.
|
/// Sets view.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -216,7 +226,7 @@ namespace FlaxEditor.Viewport.Cameras
|
|||||||
pitch += mouseDelta.Y;
|
pitch += mouseDelta.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zoom in/out
|
// Zoom in/out with mouse wheel
|
||||||
if (input.IsZooming && !input.IsRotating)
|
if (input.IsZooming && !input.IsRotating)
|
||||||
{
|
{
|
||||||
position += forward * (Viewport.MouseWheelZoomSpeedFactor * input.MouseWheelDelta * 25.0f);
|
position += forward * (Viewport.MouseWheelZoomSpeedFactor * input.MouseWheelDelta * 25.0f);
|
||||||
@@ -226,6 +236,17 @@ namespace FlaxEditor.Viewport.Cameras
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Zoom in and out by changing FOV
|
||||||
|
if (input.IsRotating && (input.ZoomInDown || input.ZoomOutDown))
|
||||||
|
{
|
||||||
|
float delta = (input.ZoomInDown ? -0.8f : 0.8f);
|
||||||
|
AdditionalZoomFOV += delta;
|
||||||
|
}
|
||||||
|
else if (!input.IsRotating)
|
||||||
|
{
|
||||||
|
AdditionalZoomFOV = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
// Move camera with the gizmo
|
// Move camera with the gizmo
|
||||||
if (input.IsOrbiting && isUsingGizmo)
|
if (input.IsOrbiting && isUsingGizmo)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,6 +51,16 @@ namespace FlaxEditor.Viewport
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsOrbiting;
|
public bool IsOrbiting;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The zoom in state.
|
||||||
|
/// </summary>
|
||||||
|
public bool ZoomInDown;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The zoom out state.
|
||||||
|
/// </summary>
|
||||||
|
public bool ZoomOutDown;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The is control down flag.
|
/// The is control down flag.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -109,6 +119,10 @@ namespace FlaxEditor.Viewport
|
|||||||
IsAltDown = window.GetKey(KeyboardKeys.Alt);
|
IsAltDown = window.GetKey(KeyboardKeys.Alt);
|
||||||
WasAltDownBefore = prevInput.WasAltDownBefore || prevInput.IsAltDown;
|
WasAltDownBefore = prevInput.WasAltDownBefore || prevInput.IsAltDown;
|
||||||
|
|
||||||
|
InputOptions inputOptions = Editor.Instance.Options.Options.Input;
|
||||||
|
ZoomInDown = window.GetKey(inputOptions.ZoomIn.Key);
|
||||||
|
ZoomOutDown = window.GetKey(inputOptions.ZoomOut.Key);
|
||||||
|
|
||||||
IsMouseRightDown = useMouse && window.GetMouseButton(MouseButton.Right);
|
IsMouseRightDown = useMouse && window.GetMouseButton(MouseButton.Right);
|
||||||
IsMouseMiddleDown = useMouse && window.GetMouseButton(MouseButton.Middle);
|
IsMouseMiddleDown = useMouse && window.GetMouseButton(MouseButton.Middle);
|
||||||
IsMouseLeftDown = useMouse && window.GetMouseButton(MouseButton.Left);
|
IsMouseLeftDown = useMouse && window.GetMouseButton(MouseButton.Left);
|
||||||
@@ -1433,7 +1447,10 @@ namespace FlaxEditor.Viewport
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
float aspect = Width / Height;
|
float aspect = Width / Height;
|
||||||
Matrix.PerspectiveFov(_fieldOfView * Mathf.DegreesToRadians, aspect, _nearPlane, _farPlane, out result);
|
float fov = _fieldOfView;
|
||||||
|
if (_camera is FPSCamera fpsCam)
|
||||||
|
fov += fpsCam.AdditionalZoomFOV;
|
||||||
|
Matrix.PerspectiveFov(fov * Mathf.DegreesToRadians, aspect, _nearPlane, _farPlane, out result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -176,7 +176,8 @@ namespace FlaxEditor.Windows
|
|||||||
if (Owner != null && (!Owner._searchPopup?.Visible ?? true))
|
if (Owner != null && (!Owner._searchPopup?.Visible ?? true))
|
||||||
{
|
{
|
||||||
// Focus back the input field as user want to modify command from history
|
// Focus back the input field as user want to modify command from history
|
||||||
Owner._searchPopup?.Hide();
|
Owner.HideHistory();
|
||||||
|
Owner.HideSearch();
|
||||||
Owner.RootWindow.Focus();
|
Owner.RootWindow.Focus();
|
||||||
Owner.Focus();
|
Owner.Focus();
|
||||||
Owner.OnKeyDown(key);
|
Owner.OnKeyDown(key);
|
||||||
@@ -209,6 +210,7 @@ namespace FlaxEditor.Windows
|
|||||||
|
|
||||||
private OutputLogWindow _window;
|
private OutputLogWindow _window;
|
||||||
private ItemsListContextMenu _searchPopup;
|
private ItemsListContextMenu _searchPopup;
|
||||||
|
private ItemsListContextMenu _historyPopup;
|
||||||
private bool _isSettingText;
|
private bool _isSettingText;
|
||||||
|
|
||||||
public CommandLineBox(float x, float y, float width, OutputLogWindow window)
|
public CommandLineBox(float x, float y, float width, OutputLogWindow window)
|
||||||
@@ -226,6 +228,24 @@ namespace FlaxEditor.Windows
|
|||||||
_isSettingText = false;
|
_isSettingText = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HideSearch()
|
||||||
|
{
|
||||||
|
if (_searchPopup != null)
|
||||||
|
{
|
||||||
|
_searchPopup.Hide();
|
||||||
|
_searchPopup = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HideHistory()
|
||||||
|
{
|
||||||
|
if (_historyPopup != null)
|
||||||
|
{
|
||||||
|
_historyPopup.Dispose();
|
||||||
|
_historyPopup = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ShowPopup(ref ItemsListContextMenu cm, IEnumerable<string> commands, string searchText = null)
|
private void ShowPopup(ref ItemsListContextMenu cm, IEnumerable<string> commands, string searchText = null)
|
||||||
{
|
{
|
||||||
if (cm == null)
|
if (cm == null)
|
||||||
@@ -295,7 +315,7 @@ namespace FlaxEditor.Windows
|
|||||||
private void OnRootWindowLostFocus()
|
private void OnRootWindowLostFocus()
|
||||||
{
|
{
|
||||||
// Prevent popup from staying active when editor window looses focus
|
// Prevent popup from staying active when editor window looses focus
|
||||||
_searchPopup?.Hide();
|
HideSearch();
|
||||||
if (RootWindow?.Window != null)
|
if (RootWindow?.Window != null)
|
||||||
RootWindow.Window.LostFocus -= OnRootWindowLostFocus;
|
RootWindow.Window.LostFocus -= OnRootWindowLostFocus;
|
||||||
}
|
}
|
||||||
@@ -330,6 +350,7 @@ namespace FlaxEditor.Windows
|
|||||||
if (isWhitespaceOnly)
|
if (isWhitespaceOnly)
|
||||||
DebugCommands.GetAllCommands(out commands);
|
DebugCommands.GetAllCommands(out commands);
|
||||||
|
|
||||||
|
HideHistory();
|
||||||
ShowPopup(ref _searchPopup, isWhitespaceOnly ? commands : matches, text);
|
ShowPopup(ref _searchPopup, isWhitespaceOnly ? commands : matches, text);
|
||||||
|
|
||||||
if (isWhitespaceOnly)
|
if (isWhitespaceOnly)
|
||||||
@@ -342,7 +363,7 @@ namespace FlaxEditor.Windows
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_searchPopup?.Hide();
|
HideSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -353,7 +374,8 @@ namespace FlaxEditor.Windows
|
|||||||
case KeyboardKeys.Return:
|
case KeyboardKeys.Return:
|
||||||
{
|
{
|
||||||
// Run command
|
// Run command
|
||||||
_searchPopup?.Hide();
|
HideSearch();
|
||||||
|
HideHistory();
|
||||||
var command = Text.Trim();
|
var command = Text.Trim();
|
||||||
if (command.Length == 0)
|
if (command.Length == 0)
|
||||||
return true;
|
return true;
|
||||||
@@ -430,9 +452,8 @@ namespace FlaxEditor.Windows
|
|||||||
if (_window._commandHistory != null && _window._commandHistory.Count != 0)
|
if (_window._commandHistory != null && _window._commandHistory.Count != 0)
|
||||||
{
|
{
|
||||||
// Show command history popup
|
// Show command history popup
|
||||||
_searchPopup?.Hide();
|
HideSearch();
|
||||||
ItemsListContextMenu cm = null;
|
ShowPopup(ref _historyPopup, _window._commandHistory);
|
||||||
ShowPopup(ref cm, _window._commandHistory);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -57,6 +57,15 @@ public:
|
|||||||
{
|
{
|
||||||
return &_knowledge;
|
return &_knowledge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the blackboard of a given type.
|
||||||
|
/// </summary>
|
||||||
|
template<typename T>
|
||||||
|
FORCE_INLINE T* GetBlackboard()
|
||||||
|
{
|
||||||
|
return _knowledge.GetBlackboard<T>();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the last behavior tree execution result.
|
/// Gets the last behavior tree execution result.
|
||||||
|
|||||||
@@ -124,6 +124,18 @@ public:
|
|||||||
RemoveGoal(T::TypeInitializer);
|
RemoveGoal(T::TypeInitializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the blackboard of a given type.
|
||||||
|
/// </summary>
|
||||||
|
template<typename T>
|
||||||
|
FORCE_INLINE T* GetBlackboard()
|
||||||
|
{
|
||||||
|
auto* structure = Blackboard.AsStructure<T>();
|
||||||
|
if (structure)
|
||||||
|
return structure;
|
||||||
|
return Cast<T>((ScriptingObject*)Blackboard);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compares two values and returns the comparision result.
|
/// Compares two values and returns the comparision result.
|
||||||
|
|||||||
@@ -11,6 +11,18 @@ using FlaxEngine.GUI;
|
|||||||
|
|
||||||
namespace FlaxEngine
|
namespace FlaxEngine
|
||||||
{
|
{
|
||||||
|
partial class Behavior
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the blackboard of the given type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"> The blackboard type.</typeparam>
|
||||||
|
public T GetBlackboard<T>()
|
||||||
|
{
|
||||||
|
return Knowledge.GetBlackboard<T>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
partial class BehaviorKnowledge
|
partial class BehaviorKnowledge
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -33,6 +45,16 @@ namespace FlaxEngine
|
|||||||
{
|
{
|
||||||
RemoveGoal(typeof(T));
|
RemoveGoal(typeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the blackboard of the given type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"> The blackboard type.</typeparam>
|
||||||
|
[Unmanaged]
|
||||||
|
public T GetBlackboard<T>()
|
||||||
|
{
|
||||||
|
return (T)Blackboard;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partial class BehaviorTreeRootNode
|
partial class BehaviorTreeRootNode
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ public class Debug : EngineModule
|
|||||||
{
|
{
|
||||||
options.PublicDefinitions.Add("COMPILE_WITH_DEBUG_DRAW");
|
options.PublicDefinitions.Add("COMPILE_WITH_DEBUG_DRAW");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.Target.IsEditor || options.Configuration != TargetConfiguration.Release)
|
||||||
|
{
|
||||||
|
// Used by DebugCommands to parse Xml documentation
|
||||||
|
options.ScriptingAPI.SystemReferences.Add("System.Xml");
|
||||||
|
options.ScriptingAPI.SystemReferences.Add("System.Xml.ReaderWriter");
|
||||||
|
options.ScriptingAPI.SystemReferences.Add("System.Text.RegularExpressions");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -16,8 +16,11 @@
|
|||||||
#include "Engine/Scripting/ManagedCLR/MMethod.h"
|
#include "Engine/Scripting/ManagedCLR/MMethod.h"
|
||||||
#include "Engine/Scripting/ManagedCLR/MField.h"
|
#include "Engine/Scripting/ManagedCLR/MField.h"
|
||||||
#include "Engine/Scripting/ManagedCLR/MProperty.h"
|
#include "Engine/Scripting/ManagedCLR/MProperty.h"
|
||||||
|
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||||
#include "FlaxEngine.Gen.h"
|
#include "FlaxEngine.Gen.h"
|
||||||
|
|
||||||
|
#define WITH_HELP (USE_EDITOR || !BUILD_RELEASE) && USE_CSHARP
|
||||||
|
|
||||||
struct CommandData
|
struct CommandData
|
||||||
{
|
{
|
||||||
String Name;
|
String Name;
|
||||||
@@ -26,6 +29,38 @@ struct CommandData
|
|||||||
void* MethodGet = nullptr;
|
void* MethodGet = nullptr;
|
||||||
void* MethodSet = nullptr;
|
void* MethodSet = nullptr;
|
||||||
void* Field = nullptr;
|
void* Field = nullptr;
|
||||||
|
#if WITH_HELP
|
||||||
|
mutable String Help;
|
||||||
|
|
||||||
|
StringView GetHelp() const
|
||||||
|
{
|
||||||
|
if (Help.IsEmpty())
|
||||||
|
{
|
||||||
|
if (dynamic_cast<ManagedBinaryModule*>(Module))
|
||||||
|
{
|
||||||
|
// Get C# type and member name
|
||||||
|
const MClass* mclass = nullptr;
|
||||||
|
StringAnsiView name;
|
||||||
|
if (auto field = (MField*)Field)
|
||||||
|
{
|
||||||
|
mclass = field->GetParentClass();
|
||||||
|
name = field->GetName();
|
||||||
|
}
|
||||||
|
else if (auto method = (MMethod*)(Method ? Method : (MethodGet ? MethodGet : MethodSet)))
|
||||||
|
{
|
||||||
|
mclass = method->GetParentClass();
|
||||||
|
name = method->GetName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use Xml docs reader used by Editor to get tooltips
|
||||||
|
auto getXmlInternal = DebugCommands::TypeInitializer.GetClass()->GetMethod("GetXmlInternal", 2);
|
||||||
|
void* params[2] = { INTERNAL_TYPE_GET_OBJECT(mclass->GetType()), MUtils::ToString(name) };
|
||||||
|
Help = MUtils::ToString((MString*)getXmlInternal->Invoke(nullptr, params, nullptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Help;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void PrettyPrint(StringBuilder& sb, const Variant& value)
|
static void PrettyPrint(StringBuilder& sb, const Variant& value)
|
||||||
{
|
{
|
||||||
@@ -122,7 +157,11 @@ struct CommandData
|
|||||||
// Parse arguments
|
// Parse arguments
|
||||||
if (args == StringView(TEXT("?"), 1))
|
if (args == StringView(TEXT("?"), 1))
|
||||||
{
|
{
|
||||||
LOG(Warning, "TODO: debug commands help/docs printing"); // TODO: debug commands help/docs printing (use CodeDocsModule that parses XML docs)
|
#if WITH_HELP
|
||||||
|
// Print command description
|
||||||
|
LOG(Info, "> {} ?", Name);
|
||||||
|
LOG_STR(Info, GetHelp());
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Array<Variant> params;
|
Array<Variant> params;
|
||||||
@@ -356,6 +395,22 @@ namespace
|
|||||||
InitCommands();
|
InitCommands();
|
||||||
Locker.Unlock();
|
Locker.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CommandData* GetCommand(StringView command)
|
||||||
|
{
|
||||||
|
if (command.FindLast(' ') != -1)
|
||||||
|
command = command.Left(command.Find(' '));
|
||||||
|
// TODO: fix missing string handle on 1st command execution (command gets invalid after InitCommands due to dotnet GC or dotnet interop handles flush)
|
||||||
|
String commandCopy = command;
|
||||||
|
command = commandCopy;
|
||||||
|
EnsureInited();
|
||||||
|
for (auto& e : Commands)
|
||||||
|
{
|
||||||
|
if (e.Name == command)
|
||||||
|
return &e;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DebugCommandsService : public EngineService
|
class DebugCommandsService : public EngineService
|
||||||
@@ -475,30 +530,32 @@ void DebugCommands::GetAllCommands(Array<StringView>& commands)
|
|||||||
DebugCommands::CommandFlags DebugCommands::GetCommandFlags(StringView command)
|
DebugCommands::CommandFlags DebugCommands::GetCommandFlags(StringView command)
|
||||||
{
|
{
|
||||||
CommandFlags result = CommandFlags::None;
|
CommandFlags result = CommandFlags::None;
|
||||||
if (command.FindLast(' ') != -1)
|
if (auto cmd = GetCommand(command))
|
||||||
command = command.Left(command.Find(' '));
|
|
||||||
// TODO: fix missing string handle on 1st command execution (command gets invalid after InitCommands due to dotnet GC or dotnet interop handles flush)
|
|
||||||
String commandCopy = command;
|
|
||||||
command = commandCopy;
|
|
||||||
EnsureInited();
|
|
||||||
for (auto& e : Commands)
|
|
||||||
{
|
{
|
||||||
if (e.Name == command)
|
if (cmd->Method)
|
||||||
{
|
result |= CommandFlags::Exec;
|
||||||
if (e.Method)
|
else if (cmd->Field)
|
||||||
result |= CommandFlags::Exec;
|
result |= CommandFlags::ReadWrite;
|
||||||
else if (e.Field)
|
if (cmd->MethodGet)
|
||||||
result |= CommandFlags::ReadWrite;
|
result |= CommandFlags::Read;
|
||||||
if (e.MethodGet)
|
if (cmd->MethodSet)
|
||||||
result |= CommandFlags::Read;
|
result |= CommandFlags::Write;
|
||||||
if (e.MethodSet)
|
|
||||||
result |= CommandFlags::Write;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringView DebugCommands::GetCommandHelp(StringView command)
|
||||||
|
{
|
||||||
|
StringView result;
|
||||||
|
#if WITH_HELP
|
||||||
|
if (auto cmd = GetCommand(command))
|
||||||
|
{
|
||||||
|
result = cmd->GetHelp();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool DebugCommands::Iterate(const StringView& searchText, int32& index)
|
bool DebugCommands::Iterate(const StringView& searchText, int32& index)
|
||||||
{
|
{
|
||||||
EnsureInited();
|
EnsureInited();
|
||||||
|
|||||||
@@ -1,6 +1,17 @@
|
|||||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#if USE_EDITOR || !BUILD_RELEASE
|
||||||
|
#define WITH_HELP
|
||||||
|
#endif
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
namespace FlaxEngine
|
namespace FlaxEngine
|
||||||
{
|
{
|
||||||
@@ -12,4 +23,331 @@ namespace FlaxEngine
|
|||||||
public sealed class DebugCommand : Attribute
|
public sealed class DebugCommand : Attribute
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial class DebugCommands
|
||||||
|
{
|
||||||
|
#if WITH_HELP
|
||||||
|
private static Dictionary<Assembly, Dictionary<string, string>> _xmlCache;
|
||||||
|
private static StringBuilder _sb;
|
||||||
|
|
||||||
|
internal static void ClearXml()
|
||||||
|
{
|
||||||
|
if (_xmlCache == null)
|
||||||
|
return;
|
||||||
|
foreach (var asm in _xmlCache.Keys.ToArray())
|
||||||
|
{
|
||||||
|
if (asm.IsCollectible)
|
||||||
|
_xmlCache.Remove(asm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string GetXmlInternal(Type type, string memberName)
|
||||||
|
{
|
||||||
|
// Redirect into type when no member specified
|
||||||
|
if (string.IsNullOrEmpty(memberName))
|
||||||
|
return GetXml(type);
|
||||||
|
|
||||||
|
// Redirect property function getter/setter into owning property docs
|
||||||
|
if (memberName.StartsWith("get_") || memberName.StartsWith("set_"))
|
||||||
|
memberName = memberName.Substring(4);
|
||||||
|
|
||||||
|
// Find member of that name
|
||||||
|
var members = type.GetMember(memberName, BindingFlags.Static | BindingFlags.Public);
|
||||||
|
if (members.Length == 0)
|
||||||
|
return null;
|
||||||
|
return GetXml(members[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the XML docs text for the type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The type.</param>
|
||||||
|
/// <returns>The documentation help.</returns>
|
||||||
|
public static string GetXml(Type type)
|
||||||
|
{
|
||||||
|
var xml = GetXmlDocs(type.Assembly);
|
||||||
|
if (xml != null)
|
||||||
|
{
|
||||||
|
var key = "T:" + GetXmlKey(type.FullName);
|
||||||
|
if (xml.TryGetValue(key, out var xmlDoc))
|
||||||
|
return FilterWhitespaces(xmlDoc);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the XML docs text for the type member.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="member">The type member.</param>
|
||||||
|
/// <returns>The documentation help.</returns>
|
||||||
|
public static string GetXml(MemberInfo member)
|
||||||
|
{
|
||||||
|
string text = null;
|
||||||
|
var xml = GetXmlDocs(member.DeclaringType.Assembly);
|
||||||
|
if (xml != null)
|
||||||
|
{
|
||||||
|
// [Reference: MSDN Magazine, October 2019, Volume 34 Number 10, "Accessing XML Documentation via Reflection"]
|
||||||
|
// https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/october/csharp-accessing-xml-documentation-via-reflection
|
||||||
|
var memberType = member.MemberType;
|
||||||
|
string key = null;
|
||||||
|
if (memberType.HasFlag(MemberTypes.Field))
|
||||||
|
{
|
||||||
|
var fieldInfo = (FieldInfo)member;
|
||||||
|
key = "F:" + GetXmlKey(fieldInfo.DeclaringType.FullName) + "." + fieldInfo.Name;
|
||||||
|
}
|
||||||
|
else if (memberType.HasFlag(MemberTypes.Property))
|
||||||
|
{
|
||||||
|
var propertyInfo = (PropertyInfo)member;
|
||||||
|
key = "P:" + GetXmlKey(propertyInfo.DeclaringType.FullName) + "." + propertyInfo.Name;
|
||||||
|
}
|
||||||
|
else if (memberType.HasFlag(MemberTypes.Event))
|
||||||
|
{
|
||||||
|
var eventInfo = (EventInfo)member;
|
||||||
|
key = "E:" + GetXmlKey(eventInfo.DeclaringType.FullName) + "." + eventInfo.Name;
|
||||||
|
}
|
||||||
|
else if (memberType.HasFlag(MemberTypes.Constructor))
|
||||||
|
{
|
||||||
|
var constructorInfo = (ConstructorInfo)member;
|
||||||
|
key = GetXmlKey(constructorInfo);
|
||||||
|
}
|
||||||
|
else if (memberType.HasFlag(MemberTypes.Method))
|
||||||
|
{
|
||||||
|
var methodInfo = (MethodInfo)member;
|
||||||
|
key = GetXmlKey(methodInfo);
|
||||||
|
}
|
||||||
|
else if (memberType.HasFlag(MemberTypes.TypeInfo) || memberType.HasFlag(MemberTypes.NestedType))
|
||||||
|
{
|
||||||
|
var typeInfo = (TypeInfo)member;
|
||||||
|
key = "T:" + GetXmlKey(typeInfo.FullName);
|
||||||
|
}
|
||||||
|
if (key != null)
|
||||||
|
{
|
||||||
|
xml.TryGetValue(key, out text);
|
||||||
|
text = FilterWhitespaces(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Customize tooltips for properties to be more human-readable in UI
|
||||||
|
if (text != null && memberType.HasFlag(MemberTypes.Property) && text.StartsWith("Gets or sets ", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
text = text.Substring(13);
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (char* e = text)
|
||||||
|
e[0] = char.ToUpper(e[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FilterWhitespaces(string str)
|
||||||
|
{
|
||||||
|
if (str != null && str.Contains(" ", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
if (_sb == null)
|
||||||
|
_sb = new StringBuilder();
|
||||||
|
else
|
||||||
|
_sb.Clear();
|
||||||
|
var sb = _sb;
|
||||||
|
var prev = str[0];
|
||||||
|
sb.Append(prev);
|
||||||
|
for (int i = 1; i < str.Length; i++)
|
||||||
|
{
|
||||||
|
var c = str[i];
|
||||||
|
if (prev != ' ' || c != ' ')
|
||||||
|
sb.Append(c);
|
||||||
|
prev = c;
|
||||||
|
}
|
||||||
|
str = sb.ToString();
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// [Reference: MSDN Magazine, October 2019, Volume 34 Number 10, "Accessing XML Documentation via Reflection"]
|
||||||
|
// https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/october/csharp-accessing-xml-documentation-via-reflection
|
||||||
|
|
||||||
|
private static string GetXmlKey(MethodInfo methodInfo)
|
||||||
|
{
|
||||||
|
var typeGenericMap = new Dictionary<string, int>();
|
||||||
|
var methodGenericMap = new Dictionary<string, int>();
|
||||||
|
ParameterInfo[] parameterInfos = methodInfo.GetParameters();
|
||||||
|
|
||||||
|
if (methodInfo.DeclaringType.IsGenericType)
|
||||||
|
{
|
||||||
|
var methods = methodInfo.DeclaringType.GetGenericTypeDefinition().GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
methodInfo = methods.First(x => x.MetadataToken == methodInfo.MetadataToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type[] typeGenericArguments = methodInfo.DeclaringType.GetGenericArguments();
|
||||||
|
for (int i = 0; i < typeGenericArguments.Length; i++)
|
||||||
|
{
|
||||||
|
Type typeGeneric = typeGenericArguments[i];
|
||||||
|
typeGenericMap[typeGeneric.Name] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type[] methodGenericArguments = methodInfo.GetGenericArguments();
|
||||||
|
for (int i = 0; i < methodGenericArguments.Length; i++)
|
||||||
|
{
|
||||||
|
Type methodGeneric = methodGenericArguments[i];
|
||||||
|
methodGenericMap[methodGeneric.Name] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
string declarationTypeString = GetXmlKey(methodInfo.DeclaringType, false, typeGenericMap, methodGenericMap);
|
||||||
|
string memberNameString = methodInfo.Name;
|
||||||
|
string methodGenericArgumentsString = methodGenericMap.Count > 0 ? "``" + methodGenericMap.Count : string.Empty;
|
||||||
|
string parametersString = parameterInfos.Length > 0 ? "(" + string.Join(",", methodInfo.GetParameters().Select(x => GetXmlKey(x.ParameterType, true, typeGenericMap, methodGenericMap))) + ")" : string.Empty;
|
||||||
|
|
||||||
|
string key = "M:" + declarationTypeString + "." + memberNameString + methodGenericArgumentsString + parametersString;
|
||||||
|
if (methodInfo.Name is "op_Implicit" || methodInfo.Name is "op_Explicit")
|
||||||
|
{
|
||||||
|
key += "~" + GetXmlKey(methodInfo.ReturnType, true, typeGenericMap, methodGenericMap);
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetXmlKey(ConstructorInfo constructorInfo)
|
||||||
|
{
|
||||||
|
var typeGenericMap = new Dictionary<string, int>();
|
||||||
|
var methodGenericMap = new Dictionary<string, int>();
|
||||||
|
ParameterInfo[] parameterInfos = constructorInfo.GetParameters();
|
||||||
|
|
||||||
|
Type[] typeGenericArguments = constructorInfo.DeclaringType.GetGenericArguments();
|
||||||
|
for (int i = 0; i < typeGenericArguments.Length; i++)
|
||||||
|
{
|
||||||
|
Type typeGeneric = typeGenericArguments[i];
|
||||||
|
typeGenericMap[typeGeneric.Name] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
string declarationTypeString = GetXmlKey(constructorInfo.DeclaringType, false, typeGenericMap, methodGenericMap);
|
||||||
|
string methodGenericArgumentsString = methodGenericMap.Count > 0 ? "``" + methodGenericMap.Count : string.Empty;
|
||||||
|
string parametersString = parameterInfos.Length > 0 ? "(" + string.Join(",", constructorInfo.GetParameters().Select(x => GetXmlKey(x.ParameterType, true, typeGenericMap, methodGenericMap))) + ")" : string.Empty;
|
||||||
|
|
||||||
|
return "M:" + declarationTypeString + "." + "#ctor" + methodGenericArgumentsString + parametersString;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string GetXmlKey(Type type, bool isMethodParameter, Dictionary<string, int> typeGenericMap, Dictionary<string, int> methodGenericMap)
|
||||||
|
{
|
||||||
|
if (type.IsGenericParameter)
|
||||||
|
{
|
||||||
|
if (methodGenericMap.TryGetValue(type.Name, out var methodIndex))
|
||||||
|
return "``" + methodIndex;
|
||||||
|
if (typeGenericMap.TryGetValue(type.Name, out var typeKey))
|
||||||
|
return "`" + typeKey;
|
||||||
|
return "`";
|
||||||
|
}
|
||||||
|
if (type.HasElementType)
|
||||||
|
{
|
||||||
|
string elementTypeString = GetXmlKey(type.GetElementType(), isMethodParameter, typeGenericMap, methodGenericMap);
|
||||||
|
if (type.IsPointer)
|
||||||
|
return elementTypeString + "*";
|
||||||
|
if (type.IsByRef)
|
||||||
|
return elementTypeString + "@";
|
||||||
|
if (type.IsArray)
|
||||||
|
{
|
||||||
|
int rank = type.GetArrayRank();
|
||||||
|
string arrayDimensionsString = rank > 1 ? "[" + string.Join(",", Enumerable.Repeat("0:", rank)) + "]" : "[]";
|
||||||
|
return elementTypeString + arrayDimensionsString;
|
||||||
|
}
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
string prefaceString = type.IsNested ? GetXmlKey(type.DeclaringType, isMethodParameter, typeGenericMap, methodGenericMap) + "." : type.Namespace + ".";
|
||||||
|
string typeNameString = isMethodParameter ? Regex.Replace(type.Name, @"`\d+", string.Empty) : type.Name;
|
||||||
|
string genericArgumentsString = type.IsGenericType && isMethodParameter ? "{" + string.Join(",", type.GetGenericArguments().Select(argument => GetXmlKey(argument, true, typeGenericMap, methodGenericMap))) + "}" : string.Empty;
|
||||||
|
return prefaceString + typeNameString + genericArgumentsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetXmlKey(string typeFullNameString)
|
||||||
|
{
|
||||||
|
return Regex.Replace(typeFullNameString, @"\[.*\]", string.Empty).Replace('+', '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, string> GetXmlDocs(Assembly assembly)
|
||||||
|
{
|
||||||
|
if (_xmlCache == null)
|
||||||
|
_xmlCache = new Dictionary<Assembly, Dictionary<string, string>>();
|
||||||
|
if (!_xmlCache.TryGetValue(assembly, out var result))
|
||||||
|
{
|
||||||
|
Profiler.BeginEvent("GetXmlDocs");
|
||||||
|
|
||||||
|
// Find XML file path (based on assembly location)
|
||||||
|
var assemblyPath = Utils.GetAssemblyLocation(assembly);
|
||||||
|
var assemblyName = assembly.GetName().Name;
|
||||||
|
var xmlFilePath = Path.ChangeExtension(assemblyPath, ".xml");
|
||||||
|
if (!File.Exists(assemblyPath) && !string.IsNullOrEmpty(assemblyPath))
|
||||||
|
{
|
||||||
|
var uri = new UriBuilder(assemblyPath);
|
||||||
|
var path = Uri.UnescapeDataString(uri.Path);
|
||||||
|
xmlFilePath = Path.Combine(Path.GetDirectoryName(path), assemblyName + ".xml");
|
||||||
|
}
|
||||||
|
if (File.Exists(xmlFilePath))
|
||||||
|
{
|
||||||
|
Profiler.BeginEvent(assemblyName);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Parse xml documentation
|
||||||
|
using (var xmlReader = XmlReader.Create(new StreamReader(xmlFilePath)))
|
||||||
|
{
|
||||||
|
result = new Dictionary<string, string>();
|
||||||
|
StringBuilder content = new StringBuilder(2048);
|
||||||
|
while (xmlReader.Read())
|
||||||
|
{
|
||||||
|
if (xmlReader.NodeType == XmlNodeType.Element && string.Equals(xmlReader.Name, "member", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
string rawName = xmlReader["name"];
|
||||||
|
var memberReader = xmlReader.ReadSubtree();
|
||||||
|
if (memberReader.ReadToDescendant("summary"))
|
||||||
|
{
|
||||||
|
content.Clear();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (memberReader.NodeType == XmlNodeType.Element && memberReader.Read())
|
||||||
|
{
|
||||||
|
while (memberReader.NodeType == XmlNodeType.Text)
|
||||||
|
{
|
||||||
|
content.Append(memberReader.Value);
|
||||||
|
if (memberReader.Read() && memberReader.NodeType == XmlNodeType.Element)
|
||||||
|
{
|
||||||
|
var nodeRef = TrimRef(memberReader.GetAttribute("cref")); // <see cref=""/>
|
||||||
|
if (nodeRef == null)
|
||||||
|
nodeRef = memberReader.GetAttribute("name"); // <paramref name=""/>
|
||||||
|
content.Append(nodeRef);
|
||||||
|
memberReader.Read();
|
||||||
|
|
||||||
|
string TrimRef(string str)
|
||||||
|
{
|
||||||
|
if (str == null)
|
||||||
|
return null;
|
||||||
|
if (str.IndexOf(":FlaxEngine.") == 1)
|
||||||
|
return str.Substring("T:FlaxEngine.".Length);
|
||||||
|
return str.Substring("T:".Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memberReader.NodeType == XmlNodeType.EndElement && memberReader.Name == "summary")
|
||||||
|
break;
|
||||||
|
} while (memberReader.Read());
|
||||||
|
|
||||||
|
result[rawName] = content.ToString().Trim(' ', '\r', '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore errors
|
||||||
|
}
|
||||||
|
Profiler.EndEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
_xmlCache[assembly] = result;
|
||||||
|
Profiler.EndEvent();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,8 +56,17 @@ public:
|
|||||||
/// Returns flags of the command.
|
/// Returns flags of the command.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="command">The full name of the command.</param>
|
/// <param name="command">The full name of the command.</param>
|
||||||
|
/// <returns>Command flags.</returns>
|
||||||
API_FUNCTION() static CommandFlags GetCommandFlags(StringView command);
|
API_FUNCTION() static CommandFlags GetCommandFlags(StringView command);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns help text of the command (from documentation comment).
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Only available in non-Release builds and Editor.</remarks>
|
||||||
|
/// <param name="command">The full name of the command.</param>
|
||||||
|
/// <returns>Command help text or empty if failed to get it.</returns>
|
||||||
|
API_FUNCTION() static StringView GetCommandHelp(StringView command);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool Iterate(const StringView& searchText, int32& index);
|
static bool Iterate(const StringView& searchText, int32& index);
|
||||||
static StringView GetCommandName(int32 index);
|
static StringView GetCommandName(int32 index);
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
namespace FlaxEngine;
|
||||||
|
|
||||||
|
partial class GameplayGlobals
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value of a given type from the global variables. (it must be added first).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the variable to retrieve.</param>
|
||||||
|
/// <typeparam name="T">The type of the variable to retrieve.</typeparam>
|
||||||
|
/// <returns>The value of the variable, or default if not found or type mismatch.</returns>
|
||||||
|
public T GetValue<T>(string name)
|
||||||
|
{
|
||||||
|
var obj = GetValue(name);
|
||||||
|
if (obj is T t)
|
||||||
|
return t;
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,8 +13,6 @@ API_CLASS(Static, Attributes="DebugCommand") class FLAXENGINE_API Globals
|
|||||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Globals);
|
DECLARE_SCRIPTING_TYPE_NO_SPAWN(Globals);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Paths
|
|
||||||
|
|
||||||
// Main engine directory path.
|
// Main engine directory path.
|
||||||
API_FIELD(ReadOnly) static String StartupFolder;
|
API_FIELD(ReadOnly) static String StartupFolder;
|
||||||
|
|
||||||
@@ -54,8 +52,6 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// State
|
|
||||||
|
|
||||||
// True if fatal error occurred (engine is exiting).
|
// True if fatal error occurred (engine is exiting).
|
||||||
// [Deprecated in v1.10]
|
// [Deprecated in v1.10]
|
||||||
DEPRECATED("Use Engine::FatalError instead.") static bool FatalErrorOccurred;
|
DEPRECATED("Use Engine::FatalError instead.") static bool FatalErrorOccurred;
|
||||||
@@ -91,14 +87,10 @@ public:
|
|||||||
DEPRECATED("Use Engine::ExitCode instead.") static int32 ExitCode;
|
DEPRECATED("Use Engine::ExitCode instead.") static int32 ExitCode;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Threading
|
|
||||||
|
|
||||||
// Main Engine thread id.
|
// Main Engine thread id.
|
||||||
API_FIELD(ReadOnly) static uint64 MainThreadID;
|
API_FIELD(ReadOnly) static uint64 MainThreadID;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Config
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The full engine version.
|
/// The full engine version.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -19,32 +19,32 @@ public:
|
|||||||
API_FIELD() static bool UseVSync;
|
API_FIELD() static bool UseVSync;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Anti Aliasing quality setting.
|
/// Anti Aliasing quality setting. Available values are: Low, Medium, High, Ultra (or 0, 1, 2, 3).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() static Quality AAQuality;
|
API_FIELD() static Quality AAQuality;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Screen Space Reflections quality setting.
|
/// Screen Space Reflections quality setting. Available values are: Low, Medium, High, Ultra (or 0, 1, 2, 3).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() static Quality SSRQuality;
|
API_FIELD() static Quality SSRQuality;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Screen Space Ambient Occlusion quality setting.
|
/// Screen Space Ambient Occlusion quality setting. Available values are: Low, Medium, High, Ultra (or 0, 1, 2, 3).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() static Quality SSAOQuality;
|
API_FIELD() static Quality SSAOQuality;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Volumetric Fog quality setting.
|
/// Volumetric Fog quality setting. Available values are: Low, Medium, High, Ultra (or 0, 1, 2, 3).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() static Quality VolumetricFogQuality;
|
API_FIELD() static Quality VolumetricFogQuality;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The shadows filtering quality (sampling).
|
/// The shadows filtering quality (sampling). Available values are: Low, Medium, High, Ultra (or 0, 1, 2, 3).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() static Quality ShadowsQuality;
|
API_FIELD() static Quality ShadowsQuality;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The shadow maps quality (textures resolution).
|
/// The shadow maps quality (textures resolution). Available values are: Low, Medium, High, Ultra (or 0, 1, 2, 3).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() static Quality ShadowMapsQuality;
|
API_FIELD() static Quality ShadowMapsQuality;
|
||||||
|
|
||||||
@@ -59,12 +59,12 @@ public:
|
|||||||
API_FIELD() static bool AllowCSMBlending;
|
API_FIELD() static bool AllowCSMBlending;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Global SDF quality. Controls the volume texture resolution and amount of cascades to use.
|
/// The Global SDF quality. Controls the volume texture resolution and amount of cascades to use. Available values are: Low, Medium, High, Ultra (or 0, 1, 2, 3).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() static Quality GlobalSDFQuality;
|
API_FIELD() static Quality GlobalSDFQuality;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Global Illumination quality. Controls the quality of the GI effect.
|
/// The Global Illumination quality. Controls the quality of the GI effect. Available values are: Low, Medium, High, Ultra (or 0, 1, 2, 3).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() static Quality GIQuality;
|
API_FIELD() static Quality GIQuality;
|
||||||
|
|
||||||
|
|||||||
@@ -507,6 +507,7 @@ void MaterialParameter::clone(const MaterialParameter* param)
|
|||||||
break;
|
break;
|
||||||
case MaterialParameterType::Integer:
|
case MaterialParameterType::Integer:
|
||||||
case MaterialParameterType::SceneTexture:
|
case MaterialParameterType::SceneTexture:
|
||||||
|
case MaterialParameterType::ChannelMask:
|
||||||
case MaterialParameterType::TextureGroupSampler:
|
case MaterialParameterType::TextureGroupSampler:
|
||||||
_asInteger = param->_asInteger;
|
_asInteger = param->_asInteger;
|
||||||
break;
|
break;
|
||||||
@@ -647,10 +648,7 @@ bool MaterialParams::Load(ReadStream* stream)
|
|||||||
PROFILE_MEM(GraphicsMaterials);
|
PROFILE_MEM(GraphicsMaterials);
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
// Release
|
Clear();
|
||||||
Resize(0);
|
|
||||||
|
|
||||||
// Check for not empty params
|
|
||||||
if (stream != nullptr && stream->CanRead())
|
if (stream != nullptr && stream->CanRead())
|
||||||
{
|
{
|
||||||
// Version
|
// Version
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ void RenderView::CopyFrom(const Camera* camera, const Viewport* viewport)
|
|||||||
const Vector3 cameraPos = camera->GetPosition();
|
const Vector3 cameraPos = camera->GetPosition();
|
||||||
LargeWorlds::UpdateOrigin(Origin, cameraPos);
|
LargeWorlds::UpdateOrigin(Origin, cameraPos);
|
||||||
Position = cameraPos - Origin;
|
Position = cameraPos - Origin;
|
||||||
Direction = camera->GetDirection();
|
Direction = camera->GetForward();
|
||||||
Near = camera->GetNearPlane();
|
Near = camera->GetNearPlane();
|
||||||
Far = camera->GetFarPlane();
|
Far = camera->GetFarPlane();
|
||||||
camera->GetMatrices(View, Projection, viewport ? *viewport : camera->GetViewport(), Origin);
|
camera->GetMatrices(View, Projection, viewport ? *viewport : camera->GetViewport(), Origin);
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ namespace FlaxEngine
|
|||||||
Vector3 cameraPos = camera.Position;
|
Vector3 cameraPos = camera.Position;
|
||||||
LargeWorlds.UpdateOrigin(ref Origin, cameraPos);
|
LargeWorlds.UpdateOrigin(ref Origin, cameraPos);
|
||||||
Position = cameraPos - Origin;
|
Position = cameraPos - Origin;
|
||||||
Direction = camera.Direction;
|
Direction = camera.Forward;
|
||||||
Near = camera.NearPlane;
|
Near = camera.NearPlane;
|
||||||
Far = camera.FarPlane;
|
Far = camera.FarPlane;
|
||||||
camera.GetMatrices(out View, out Projection, ref viewport, ref Origin);
|
camera.GetMatrices(out View, out Projection, ref viewport, ref Origin);
|
||||||
|
|||||||
@@ -360,14 +360,12 @@ bool ShaderAssetBase::LoadShaderCache(ShaderCacheResult& result)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(result.Data.IsValid());
|
|
||||||
|
|
||||||
#if COMPILE_WITH_SHADER_COMPILER
|
#if COMPILE_WITH_SHADER_COMPILER
|
||||||
// Read includes from cache
|
// Read includes from cache
|
||||||
IsValidShaderCache(result.Data, result.Includes);
|
IsValidShaderCache(result.Data, result.Includes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return false;
|
return result.Data.IsInvalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if COMPILE_WITH_SHADER_COMPILER
|
#if COMPILE_WITH_SHADER_COMPILER
|
||||||
|
|||||||
@@ -822,6 +822,11 @@ void Actor::SetRotation(const Matrix& value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Actor::SetDirection(const Float3& value)
|
void Actor::SetDirection(const Float3& value)
|
||||||
|
{
|
||||||
|
SetForward(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::SetForward(const Float3& value)
|
||||||
{
|
{
|
||||||
CHECK(!value.IsNanOrInfinity());
|
CHECK(!value.IsNanOrInfinity());
|
||||||
Quaternion orientation;
|
Quaternion orientation;
|
||||||
@@ -1714,17 +1719,22 @@ Actor* Actor::Intersects(const Ray& ray, Real& distance, Vector3& normal)
|
|||||||
|
|
||||||
void Actor::LookAt(const Vector3& worldPos)
|
void Actor::LookAt(const Vector3& worldPos)
|
||||||
{
|
{
|
||||||
const Quaternion orientation = LookingAt(worldPos);
|
const Quaternion orientation = GetLookAtDirection(worldPos);
|
||||||
SetOrientation(orientation);
|
SetOrientation(orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actor::LookAt(const Vector3& worldPos, const Vector3& worldUp)
|
void Actor::LookAt(const Vector3& worldPos, const Vector3& worldUp)
|
||||||
{
|
{
|
||||||
const Quaternion orientation = LookingAt(worldPos, worldUp);
|
const Quaternion orientation = GetLookAtDirection(worldPos, worldUp);
|
||||||
SetOrientation(orientation);
|
SetOrientation(orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Quaternion Actor::LookingAt(const Vector3& worldPos) const
|
Quaternion Actor::LookingAt(const Vector3& worldPos) const
|
||||||
|
{
|
||||||
|
return GetLookAtDirection(worldPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion Actor::GetLookAtDirection(const Vector3& worldPos) const
|
||||||
{
|
{
|
||||||
const Vector3 direction = worldPos - _transform.Translation;
|
const Vector3 direction = worldPos - _transform.Translation;
|
||||||
if (direction.LengthSquared() < ZeroTolerance)
|
if (direction.LengthSquared() < ZeroTolerance)
|
||||||
@@ -1752,16 +1762,20 @@ Quaternion Actor::LookingAt(const Vector3& worldPos) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
Quaternion Actor::LookingAt(const Vector3& worldPos, const Vector3& worldUp) const
|
Quaternion Actor::LookingAt(const Vector3& worldPos, const Vector3& worldUp) const
|
||||||
|
{
|
||||||
|
return GetLookAtDirection(worldPos, worldUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion Actor::GetLookAtDirection(const Vector3& worldPos, const Vector3& worldUp) const
|
||||||
{
|
{
|
||||||
const Vector3 direction = worldPos - _transform.Translation;
|
const Vector3 direction = worldPos - _transform.Translation;
|
||||||
if (direction.LengthSquared() < ZeroTolerance)
|
if (direction.LengthSquared() < ZeroTolerance)
|
||||||
return _parent ? _parent->GetOrientation() : Quaternion::Identity;
|
return _parent ? _parent->GetOrientation() : Quaternion::Identity;
|
||||||
|
|
||||||
const Float3 forward = Vector3::Normalize(direction);
|
const Float3 forward = Vector3::Normalize(direction);
|
||||||
const Float3 up = Vector3::Normalize(worldUp);
|
const Float3 up = Vector3::Normalize(worldUp);
|
||||||
if (Math::IsOne(Float3::Dot(forward, up)))
|
if (Math::IsOne(Float3::Dot(forward, up)))
|
||||||
{
|
return GetLookAtDirection(worldPos);
|
||||||
return LookingAt(worldPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
Quaternion orientation;
|
Quaternion orientation;
|
||||||
Quaternion::LookRotation(direction, up, orientation);
|
Quaternion::LookRotation(direction, up, orientation);
|
||||||
|
|||||||
@@ -549,17 +549,35 @@ public:
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets actor direction vector (forward vector).
|
/// Gets actor direction vector (forward vector).
|
||||||
|
/// [Deprecated in v1.13]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_PROPERTY(Attributes="HideInEditor, NoSerialize") FORCE_INLINE Float3 GetDirection() const
|
API_PROPERTY(Attributes="HideInEditor, NoSerialize") DEPRECATED("Use GetForward instead.")
|
||||||
|
FORCE_INLINE Float3 GetDirection() const
|
||||||
|
{
|
||||||
|
return GetForward();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the actor's forward vector (direction).
|
||||||
|
/// </summary>
|
||||||
|
API_PROPERTY(Attributes="HideInEditor, NoSerialize") FORCE_INLINE Float3 GetForward() const
|
||||||
{
|
{
|
||||||
return Float3::Transform(Float3::Forward, GetOrientation());
|
return Float3::Transform(Float3::Forward, GetOrientation());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets actor direction vector (forward)
|
/// Sets actor direction vector (forward)
|
||||||
|
/// [Deprecated in v1.13]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The value to set.</param>
|
/// <param name="value">The value to set.</param>
|
||||||
API_PROPERTY() void SetDirection(const Float3& value);
|
API_PROPERTY() DEPRECATED("Use SetForward instead.")
|
||||||
|
void SetDirection(const Float3& value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rotates the actor to align its forward vector with the passed in value (direction).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to align to.</param>
|
||||||
|
API_PROPERTY() void SetForward(const Float3& value);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -897,16 +915,31 @@ public:
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets rotation of the actor oriented towards the specified world position.
|
/// Gets rotation of the actor oriented towards the specified world position.
|
||||||
|
/// [Deprecated in v1.13]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="worldPos">The world position to orient towards.</param>
|
/// <param name="worldPos">The world position to orient towards.</param>
|
||||||
API_FUNCTION() Quaternion LookingAt(const Vector3& worldPos) const;
|
API_FUNCTION() DEPRECATED("Use GetLookAtDirection instead.") Quaternion LookingAt(const Vector3& worldPos) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets rotation of the actor oriented towards the specified world position.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="worldPos">The world position to orient towards.</param>
|
||||||
|
API_FUNCTION() Quaternion GetLookAtDirection(const Vector3& worldPos) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets rotation of the actor oriented towards the specified world position with upwards direction.
|
||||||
|
/// [Deprecated in v1.13]
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="worldPos">The world position to orient towards.</param>
|
||||||
|
/// <param name="worldUp">The up direction that constrains up axis orientation to a plane this vector lies on. This rule might be broken if forward and up direction are nearly parallel.</param>
|
||||||
|
API_FUNCTION() DEPRECATED("Use GetLookAtDirection instead.") Quaternion LookingAt(const Vector3& worldPos, const Vector3& worldUp) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets rotation of the actor oriented towards the specified world position with upwards direction.
|
/// Gets rotation of the actor oriented towards the specified world position with upwards direction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="worldPos">The world position to orient towards.</param>
|
/// <param name="worldPos">The world position to orient towards.</param>
|
||||||
/// <param name="worldUp">The up direction that constrains up axis orientation to a plane this vector lies on. This rule might be broken if forward and up direction are nearly parallel.</param>
|
/// <param name="worldUp">The up direction that constrains up axis orientation to a plane this vector lies on. This rule might be broken if forward and up direction are nearly parallel.</param>
|
||||||
API_FUNCTION() Quaternion LookingAt(const Vector3& worldPos, const Vector3& worldUp) const;
|
API_FUNCTION() Quaternion GetLookAtDirection(const Vector3& worldPos, const Vector3& worldUp) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ Ray Camera::ConvertMouseToRay(const Float2& mousePosition, const Viewport& viewp
|
|||||||
{
|
{
|
||||||
Vector3 position = GetPosition();
|
Vector3 position = GetPosition();
|
||||||
if (viewport.Width < ZeroTolerance || viewport.Height < ZeroTolerance || mousePosition.IsNaN())
|
if (viewport.Width < ZeroTolerance || viewport.Height < ZeroTolerance || mousePosition.IsNaN())
|
||||||
return Ray(position, GetDirection());
|
return Ray(position, GetForward());
|
||||||
|
|
||||||
// Use different logic in orthographic projection
|
// Use different logic in orthographic projection
|
||||||
if (!_usePerspective)
|
if (!_usePerspective)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ void DirectionalLight::Draw(RenderContext& renderContext)
|
|||||||
data.ShadowsDistance = ShadowsDistance;
|
data.ShadowsDistance = ShadowsDistance;
|
||||||
data.Color = color;
|
data.Color = color;
|
||||||
data.ShadowsStrength = ShadowsStrength;
|
data.ShadowsStrength = ShadowsStrength;
|
||||||
data.Direction = GetDirection();
|
data.Direction = GetForward();
|
||||||
data.ShadowsFadeDistance = ShadowsFadeDistance;
|
data.ShadowsFadeDistance = ShadowsFadeDistance;
|
||||||
data.ShadowsNormalOffsetScale = ShadowsNormalOffsetScale;
|
data.ShadowsNormalOffsetScale = ShadowsNormalOffsetScale;
|
||||||
data.ShadowsDepthBias = ShadowsDepthBias;
|
data.ShadowsDepthBias = ShadowsDepthBias;
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ void ExponentialHeightFog::GetExponentialHeightFogData(const RenderView& view, S
|
|||||||
result.FogCutoffDistance = FogCutoffDistance >= 0 ? FogCutoffDistance : view.Far + FogCutoffDistance;
|
result.FogCutoffDistance = FogCutoffDistance >= 0 ? FogCutoffDistance : view.Far + FogCutoffDistance;
|
||||||
if (useDirectionalLightInscattering)
|
if (useDirectionalLightInscattering)
|
||||||
{
|
{
|
||||||
result.InscatteringLightDirection = -DirectionalInscatteringLight->GetDirection();
|
result.InscatteringLightDirection = -DirectionalInscatteringLight->GetForward();
|
||||||
result.DirectionalInscatteringColor = DirectionalInscatteringColor.ToFloat3();
|
result.DirectionalInscatteringColor = DirectionalInscatteringColor.ToFloat3();
|
||||||
result.DirectionalInscatteringExponent = Math::Clamp(DirectionalInscatteringExponent, 0.000001f, 1000.0f);
|
result.DirectionalInscatteringExponent = Math::Clamp(DirectionalInscatteringExponent, 0.000001f, 1000.0f);
|
||||||
result.DirectionalInscatteringStartDistance = Math::Min(DirectionalInscatteringStartDistance, view.Far - 1.0f);
|
result.DirectionalInscatteringStartDistance = Math::Min(DirectionalInscatteringStartDistance, view.Far - 1.0f);
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ void Sky::InitConfig(ShaderAtmosphericFogData& config) const
|
|||||||
|
|
||||||
if (SunLight)
|
if (SunLight)
|
||||||
{
|
{
|
||||||
config.AtmosphericFogSunDirection = -SunLight->GetDirection();
|
config.AtmosphericFogSunDirection = -SunLight->GetForward();
|
||||||
config.AtmosphericFogSunColor = SunLight->Color.ToFloat3() * SunLight->Color.A;
|
config.AtmosphericFogSunColor = SunLight->Color.ToFloat3() * SunLight->Color.A;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ SpotLight::SpotLight(const SpawnParams& params)
|
|||||||
_cosInnerCone = Math::Cos(_innerConeAngle * DegreesToRadians);
|
_cosInnerCone = Math::Cos(_innerConeAngle * DegreesToRadians);
|
||||||
_invCosConeDifference = 1.0f / (_cosInnerCone - _cosOuterCone);
|
_invCosConeDifference = 1.0f / (_cosInnerCone - _cosOuterCone);
|
||||||
const float boundsRadius = Math::Sqrt(1.25f * _radius * _radius - _radius * _radius * _cosOuterCone);
|
const float boundsRadius = Math::Sqrt(1.25f * _radius * _radius - _radius * _radius * _cosOuterCone);
|
||||||
_sphere = BoundingSphere(GetPosition() + 0.5f * GetDirection() * _radius, boundsRadius);
|
_sphere = BoundingSphere(GetPosition() + 0.5f * GetForward() * _radius, boundsRadius);
|
||||||
BoundingBox::FromSphere(_sphere, _box);
|
BoundingBox::FromSphere(_sphere, _box);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ void SpotLight::UpdateBounds()
|
|||||||
// Note: we use the law of cosines to find the distance to the furthest edge of the spotlight cone from a position that is halfway down the spotlight direction
|
// Note: we use the law of cosines to find the distance to the furthest edge of the spotlight cone from a position that is halfway down the spotlight direction
|
||||||
const float radius = GetScaledRadius();
|
const float radius = GetScaledRadius();
|
||||||
const float boundsRadius = Math::Sqrt(1.25f * radius * radius - radius * radius * _cosOuterCone);
|
const float boundsRadius = Math::Sqrt(1.25f * radius * radius - radius * radius * _cosOuterCone);
|
||||||
_sphere = BoundingSphere(GetPosition() + 0.5f * GetDirection() * radius, boundsRadius);
|
_sphere = BoundingSphere(GetPosition() + 0.5f * GetForward() * radius, boundsRadius);
|
||||||
BoundingBox::FromSphere(_sphere, _box);
|
BoundingBox::FromSphere(_sphere, _box);
|
||||||
|
|
||||||
if (_sceneRenderingKey != -1)
|
if (_sceneRenderingKey != -1)
|
||||||
@@ -199,7 +199,7 @@ void SpotLight::OnDebugDrawSelected()
|
|||||||
const auto color = Color::Yellow;
|
const auto color = Color::Yellow;
|
||||||
Vector3 right = _transform.GetRight();
|
Vector3 right = _transform.GetRight();
|
||||||
Vector3 up = _transform.GetUp();
|
Vector3 up = _transform.GetUp();
|
||||||
Vector3 forward = GetDirection();
|
Vector3 forward = GetForward();
|
||||||
float radius = GetScaledRadius();
|
float radius = GetScaledRadius();
|
||||||
float discRadius = radius * Math::Tan(_outerConeAngle * DegreesToRadians);
|
float discRadius = radius * Math::Tan(_outerConeAngle * DegreesToRadians);
|
||||||
float falloffDiscRadius = radius * Math::Tan(_innerConeAngle * DegreesToRadians);
|
float falloffDiscRadius = radius * Math::Tan(_innerConeAngle * DegreesToRadians);
|
||||||
@@ -231,7 +231,7 @@ void SpotLight::DrawLightsDebug(RenderView& view)
|
|||||||
const auto color = Color::Yellow;
|
const auto color = Color::Yellow;
|
||||||
Vector3 right = _transform.GetRight();
|
Vector3 right = _transform.GetRight();
|
||||||
Vector3 up = _transform.GetUp();
|
Vector3 up = _transform.GetUp();
|
||||||
Vector3 forward = GetDirection();
|
Vector3 forward = GetForward();
|
||||||
float radius = GetScaledRadius();
|
float radius = GetScaledRadius();
|
||||||
float discRadius = radius * Math::Tan(_outerConeAngle * DegreesToRadians);
|
float discRadius = radius * Math::Tan(_outerConeAngle * DegreesToRadians);
|
||||||
float falloffDiscRadius = radius * Math::Tan(_innerConeAngle * DegreesToRadians);
|
float falloffDiscRadius = radius * Math::Tan(_innerConeAngle * DegreesToRadians);
|
||||||
|
|||||||
@@ -1636,7 +1636,7 @@ FORCE_INLINE StringAnsiView GetPropertyMethodName(MProperty* property, StringAns
|
|||||||
Platform::MemoryCopy(mem, prefix.Get(), prefix.Length());
|
Platform::MemoryCopy(mem, prefix.Get(), prefix.Length());
|
||||||
Platform::MemoryCopy(mem + prefix.Length(), name.Get(), name.Length());
|
Platform::MemoryCopy(mem + prefix.Length(), name.Get(), name.Length());
|
||||||
mem[name.Length() + prefix.Length()] = 0;
|
mem[name.Length() + prefix.Length()] = 0;
|
||||||
return StringAnsiView(mem, name.Length() + prefix.Length() + 1);
|
return StringAnsiView(mem, name.Length() + prefix.Length());
|
||||||
}
|
}
|
||||||
|
|
||||||
MProperty::MProperty(MClass* parentClass, const char* name, void* handle, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes)
|
MProperty::MProperty(MClass* parentClass, const char* name, void* handle, void* getterHandle, void* setterHandle, MMethodAttributes getterAttributes, MMethodAttributes setterAttributes)
|
||||||
|
|||||||
@@ -465,7 +465,7 @@ namespace FlaxEngine
|
|||||||
Quaternion.Euler(180, 180, 0, out var quat);
|
Quaternion.Euler(180, 180, 0, out var quat);
|
||||||
Matrix.RotationQuaternion(ref quat, out m2);
|
Matrix.RotationQuaternion(ref quat, out m2);
|
||||||
Matrix.Multiply(ref m3, ref m2, out m1);
|
Matrix.Multiply(ref m3, ref m2, out m1);
|
||||||
m2 = Matrix.Transformation(Vector3.One, Quaternion.FromDirection(-camera.Direction), translation);
|
m2 = Matrix.Transformation(Vector3.One, Quaternion.FromDirection(-camera.Forward), translation);
|
||||||
Matrix.Multiply(ref m1, ref m2, out world);
|
Matrix.Multiply(ref m1, ref m2, out world);
|
||||||
}
|
}
|
||||||
else if (_renderMode == CanvasRenderMode.CameraSpace && camera)
|
else if (_renderMode == CanvasRenderMode.CameraSpace && camera)
|
||||||
|
|||||||
@@ -174,6 +174,30 @@ public:
|
|||||||
return _state;
|
return _state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value that determines whether the video playback is playing.
|
||||||
|
/// </summary>
|
||||||
|
API_PROPERTY() FORCE_INLINE bool IsPlaying() const
|
||||||
|
{
|
||||||
|
return _state == States::Playing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value that determines whether the video playback is paused.
|
||||||
|
/// </summary>
|
||||||
|
API_PROPERTY() FORCE_INLINE bool IsPaused() const
|
||||||
|
{
|
||||||
|
return _state == States::Paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value that determines whether the video playback is stopped.
|
||||||
|
/// </summary>
|
||||||
|
API_PROPERTY() FORCE_INLINE bool IsStopped() const
|
||||||
|
{
|
||||||
|
return _state == States::Stopped;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current time of playback. The time is in seconds, in range [0, Duration].
|
/// Gets the current time of playback. The time is in seconds, in range [0, Duration].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1054,7 +1054,8 @@ namespace Flax.Build.Bindings
|
|||||||
propertyInfo.Getter = functionInfo;
|
propertyInfo.Getter = functionInfo;
|
||||||
else
|
else
|
||||||
propertyInfo.Setter = functionInfo;
|
propertyInfo.Setter = functionInfo;
|
||||||
propertyInfo.DeprecatedMessage = functionInfo.DeprecatedMessage;
|
if (propertyInfo.DeprecatedMessage == null)
|
||||||
|
propertyInfo.DeprecatedMessage = functionInfo.DeprecatedMessage;
|
||||||
propertyInfo.IsHidden |= functionInfo.IsHidden;
|
propertyInfo.IsHidden |= functionInfo.IsHidden;
|
||||||
|
|
||||||
if (propertyInfo.Getter != null && propertyInfo.Setter != null)
|
if (propertyInfo.Getter != null && propertyInfo.Setter != null)
|
||||||
|
|||||||
Reference in New Issue
Block a user