Merge remote-tracking branch 'origin/master' into 1.10
This commit is contained in:
@@ -66,27 +66,23 @@ namespace AnimationUtils
|
||||
}
|
||||
|
||||
template<class T>
|
||||
FORCE_INLINE static void GetTangent(const T& a, const T& b, float length, T& result)
|
||||
FORCE_INLINE static void GetTangent(const T& value, const T& tangent, float tangentScale, T& result)
|
||||
{
|
||||
const float oneThird = 1.0f / 3.0f;
|
||||
result = a + b * (length * oneThird);
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
template<>
|
||||
FORCE_INLINE void GetTangent<Quaternion>(const Quaternion& a, const Quaternion& b, float length, Quaternion& result)
|
||||
FORCE_INLINE void GetTangent<Quaternion>(const Quaternion& value, const Quaternion& tangent, float tangentScale, Quaternion& result)
|
||||
{
|
||||
const float oneThird = 1.0f / 3.0f;
|
||||
Quaternion::Slerp(a, b, oneThird, result);
|
||||
Quaternion::Slerp(value, tangent, 1.0f / 3.0f, result);
|
||||
}
|
||||
|
||||
template<>
|
||||
FORCE_INLINE void GetTangent<Transform>(const Transform& a, const Transform& b, float length, Transform& result)
|
||||
FORCE_INLINE void GetTangent<Transform>(const Transform& value, const Transform& tangent, float tangentScale, Transform& result)
|
||||
{
|
||||
const float oneThird = 1.0f / 3.0f;
|
||||
const float oneThirdLength = length * oneThird;
|
||||
result.Translation = a.Translation + b.Translation * oneThirdLength;
|
||||
Quaternion::Slerp(a.Orientation, b.Orientation, oneThird, result.Orientation);
|
||||
result.Scale = a.Scale + (b.Scale - a.Scale) * oneThirdLength;
|
||||
GetTangent(value.Translation, tangent.Translation, tangentScale, result.Translation);
|
||||
GetTangent(value.Orientation, tangent.Orientation, tangentScale, result.Orientation);
|
||||
GetTangent(value.Scale, tangent.Scale, tangentScale, result.Scale);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine.Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace FlaxEngine
|
||||
@@ -24,9 +26,9 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <param name="tangent">The tangent.</param>
|
||||
/// <param name="lengthThird">The length divided by 3.</param>
|
||||
/// <param name="tangentScale">The tangent scale factor.</param>
|
||||
/// <param name="result">The result.</param>
|
||||
void GetTangent(ref U value, ref U tangent, float lengthThird, out U result);
|
||||
void GetTangent(ref U value, ref U tangent, float tangentScale, out U result);
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the linear interpolation at the specified alpha.
|
||||
@@ -67,7 +69,7 @@ namespace FlaxEngine
|
||||
IKeyframeAccess<Color32>,
|
||||
IKeyframeAccess<Color>
|
||||
{
|
||||
public void GetTangent(ref bool value, ref bool tangent, float lengthThird, out bool result)
|
||||
public void GetTangent(ref bool value, ref bool tangent, float tangentScale, out bool result)
|
||||
{
|
||||
result = value;
|
||||
}
|
||||
@@ -82,9 +84,9 @@ namespace FlaxEngine
|
||||
result = p0;
|
||||
}
|
||||
|
||||
public void GetTangent(ref int value, ref int tangent, float lengthThird, out int result)
|
||||
public void GetTangent(ref int value, ref int tangent, float tangentScale, out int result)
|
||||
{
|
||||
result = value + (int)(tangent * lengthThird);
|
||||
result = value + (int)(tangent * tangentScale);
|
||||
}
|
||||
|
||||
public void Linear(ref int a, ref int b, float alpha, out int result)
|
||||
@@ -102,9 +104,9 @@ namespace FlaxEngine
|
||||
result = Mathf.Lerp(p012, p123, alpha);
|
||||
}
|
||||
|
||||
public void GetTangent(ref double value, ref double tangent, float lengthThird, out double result)
|
||||
public void GetTangent(ref double value, ref double tangent, float tangentScale, out double result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref double a, ref double b, float alpha, out double result)
|
||||
@@ -122,9 +124,9 @@ namespace FlaxEngine
|
||||
result = Mathf.Lerp(p012, p123, alpha);
|
||||
}
|
||||
|
||||
public void GetTangent(ref float value, ref float tangent, float lengthThird, out float result)
|
||||
public void GetTangent(ref float value, ref float tangent, float tangentScale, out float result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref float a, ref float b, float alpha, out float result)
|
||||
@@ -142,9 +144,9 @@ namespace FlaxEngine
|
||||
result = Mathf.Lerp(p012, p123, alpha);
|
||||
}
|
||||
|
||||
public void GetTangent(ref Vector2 value, ref Vector2 tangent, float lengthThird, out Vector2 result)
|
||||
public void GetTangent(ref Vector2 value, ref Vector2 tangent, float tangentScale, out Vector2 result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref Vector2 a, ref Vector2 b, float alpha, out Vector2 result)
|
||||
@@ -162,9 +164,9 @@ namespace FlaxEngine
|
||||
Vector2.Lerp(ref p012, ref p123, alpha, out result);
|
||||
}
|
||||
|
||||
public void GetTangent(ref Vector3 value, ref Vector3 tangent, float lengthThird, out Vector3 result)
|
||||
public void GetTangent(ref Vector3 value, ref Vector3 tangent, float tangentScale, out Vector3 result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref Vector3 a, ref Vector3 b, float alpha, out Vector3 result)
|
||||
@@ -182,9 +184,9 @@ namespace FlaxEngine
|
||||
Vector3.Lerp(ref p012, ref p123, alpha, out result);
|
||||
}
|
||||
|
||||
public void GetTangent(ref Vector4 value, ref Vector4 tangent, float lengthThird, out Vector4 result)
|
||||
public void GetTangent(ref Vector4 value, ref Vector4 tangent, float tangentScale, out Vector4 result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref Vector4 a, ref Vector4 b, float alpha, out Vector4 result)
|
||||
@@ -202,9 +204,9 @@ namespace FlaxEngine
|
||||
Vector4.Lerp(ref p012, ref p123, alpha, out result);
|
||||
}
|
||||
|
||||
public void GetTangent(ref Float2 value, ref Float2 tangent, float lengthThird, out Float2 result)
|
||||
public void GetTangent(ref Float2 value, ref Float2 tangent, float tangentScale, out Float2 result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref Float2 a, ref Float2 b, float alpha, out Float2 result)
|
||||
@@ -222,9 +224,9 @@ namespace FlaxEngine
|
||||
Float2.Lerp(ref p012, ref p123, alpha, out result);
|
||||
}
|
||||
|
||||
public void GetTangent(ref Float3 value, ref Float3 tangent, float lengthThird, out Float3 result)
|
||||
public void GetTangent(ref Float3 value, ref Float3 tangent, float tangentScale, out Float3 result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref Float3 a, ref Float3 b, float alpha, out Float3 result)
|
||||
@@ -242,9 +244,9 @@ namespace FlaxEngine
|
||||
Float3.Lerp(ref p012, ref p123, alpha, out result);
|
||||
}
|
||||
|
||||
public void GetTangent(ref Float4 value, ref Float4 tangent, float lengthThird, out Float4 result)
|
||||
public void GetTangent(ref Float4 value, ref Float4 tangent, float tangentScale, out Float4 result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref Float4 a, ref Float4 b, float alpha, out Float4 result)
|
||||
@@ -262,9 +264,9 @@ namespace FlaxEngine
|
||||
Float4.Lerp(ref p012, ref p123, alpha, out result);
|
||||
}
|
||||
|
||||
public void GetTangent(ref Double2 value, ref Double2 tangent, float lengthThird, out Double2 result)
|
||||
public void GetTangent(ref Double2 value, ref Double2 tangent, float tangentScale, out Double2 result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref Double2 a, ref Double2 b, float alpha, out Double2 result)
|
||||
@@ -282,9 +284,9 @@ namespace FlaxEngine
|
||||
Double2.Lerp(ref p012, ref p123, alpha, out result);
|
||||
}
|
||||
|
||||
public void GetTangent(ref Double3 value, ref Double3 tangent, float lengthThird, out Double3 result)
|
||||
public void GetTangent(ref Double3 value, ref Double3 tangent, float tangentScale, out Double3 result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref Double3 a, ref Double3 b, float alpha, out Double3 result)
|
||||
@@ -302,9 +304,9 @@ namespace FlaxEngine
|
||||
Double3.Lerp(ref p012, ref p123, alpha, out result);
|
||||
}
|
||||
|
||||
public void GetTangent(ref Double4 value, ref Double4 tangent, float lengthThird, out Double4 result)
|
||||
public void GetTangent(ref Double4 value, ref Double4 tangent, float tangentScale, out Double4 result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref Double4 a, ref Double4 b, float alpha, out Double4 result)
|
||||
@@ -322,7 +324,7 @@ namespace FlaxEngine
|
||||
Double4.Lerp(ref p012, ref p123, alpha, out result);
|
||||
}
|
||||
|
||||
public void GetTangent(ref Quaternion value, ref Quaternion tangent, float lengthThird, out Quaternion result)
|
||||
public void GetTangent(ref Quaternion value, ref Quaternion tangent, float tangentScale, out Quaternion result)
|
||||
{
|
||||
Quaternion.Slerp(ref value, ref tangent, 1.0f / 3.0f, out result);
|
||||
}
|
||||
@@ -342,9 +344,9 @@ namespace FlaxEngine
|
||||
Quaternion.Slerp(ref p012, ref p123, alpha, out result);
|
||||
}
|
||||
|
||||
public void GetTangent(ref Color32 value, ref Color32 tangent, float lengthThird, out Color32 result)
|
||||
public void GetTangent(ref Color32 value, ref Color32 tangent, float tangentScale, out Color32 result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref Color32 a, ref Color32 b, float alpha, out Color32 result)
|
||||
@@ -362,9 +364,9 @@ namespace FlaxEngine
|
||||
Color32.Lerp(ref p012, ref p123, alpha, out result);
|
||||
}
|
||||
|
||||
public void GetTangent(ref Color value, ref Color tangent, float lengthThird, out Color result)
|
||||
public void GetTangent(ref Color value, ref Color tangent, float tangentScale, out Color result)
|
||||
{
|
||||
result = value + tangent * lengthThird;
|
||||
result = value + tangent * tangentScale;
|
||||
}
|
||||
|
||||
public void Linear(ref Color a, ref Color b, float alpha, out Color result)
|
||||
@@ -454,6 +456,40 @@ namespace FlaxEngine
|
||||
time = end;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raw memory copy (used by scripting bindings - see MarshalAs tag).
|
||||
/// </summary>
|
||||
/// <param name="keyframes">The keyframes array.</param>
|
||||
/// <returns>The raw keyframes data.</returns>
|
||||
protected static unsafe byte[] MarshalKeyframes<Keyframe>(Keyframe[] keyframes)
|
||||
{
|
||||
if (keyframes == null || keyframes.Length == 0)
|
||||
return null;
|
||||
var keyframeSize = Unsafe.SizeOf<Keyframe>();
|
||||
var result = new byte[keyframes.Length * keyframeSize];
|
||||
fixed (byte* resultPtr = result)
|
||||
{
|
||||
var keyframesHandle = ManagedHandle.Alloc(keyframes, GCHandleType.Pinned);
|
||||
var keyframesPtr = Marshal.UnsafeAddrOfPinnedArrayElement(keyframes, 0);
|
||||
Buffer.MemoryCopy((void*)keyframesPtr, resultPtr, (uint)result.Length, (uint)result.Length);
|
||||
keyframesHandle.Free();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raw memory copy (used by scripting bindings - see MarshalAs tag).
|
||||
/// </summary>
|
||||
/// <param name="raw">The raw keyframes data.</param>
|
||||
/// <returns>The keyframes array.</returns>
|
||||
protected static unsafe Keyframe[] MarshalKeyframes<Keyframe>(byte[] raw) where Keyframe : struct
|
||||
{
|
||||
if (raw == null || raw.Length == 0)
|
||||
return null;
|
||||
fixed (byte* rawPtr = raw)
|
||||
return MemoryMarshal.Cast<byte, Keyframe>(new Span<byte>(rawPtr, raw.Length)).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -709,6 +745,30 @@ namespace FlaxEngine
|
||||
leftKey = Mathf.Max(0, start - 1);
|
||||
rightKey = Mathf.Min(start, Keyframes.Length - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raw memory copy (used by scripting bindings - see MarshalAs tag).
|
||||
/// </summary>
|
||||
/// <param name="curve">The curve to copy.</param>
|
||||
/// <returns>The raw keyframes data.</returns>
|
||||
public static unsafe implicit operator byte[](LinearCurve<T> curve)
|
||||
{
|
||||
if (curve == null)
|
||||
return null;
|
||||
return MarshalKeyframes<Keyframe>(curve.Keyframes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raw memory copy (used by scripting bindings - see MarshalAs tag).
|
||||
/// </summary>
|
||||
/// <param name="raw">The raw keyframes data.</param>
|
||||
/// <returns>The curve.</returns>
|
||||
public static unsafe implicit operator LinearCurve<T>(byte[] raw)
|
||||
{
|
||||
if (raw == null || raw.Length == 0)
|
||||
return null;
|
||||
return new LinearCurve<T>(MarshalKeyframes<Keyframe>(raw));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -860,9 +920,9 @@ namespace FlaxEngine
|
||||
|
||||
// Evaluate the key at the curve
|
||||
result.Time = leftKey.Time + length * t;
|
||||
float lengthThird = length / 3.0f;
|
||||
_accessor.GetTangent(ref leftKey.Value, ref leftKey.TangentOut, lengthThird, out var leftTangent);
|
||||
_accessor.GetTangent(ref rightKey.Value, ref rightKey.TangentIn, lengthThird, out var rightTangent);
|
||||
float tangentScale = length / 3.0f;
|
||||
_accessor.GetTangent(ref leftKey.Value, ref leftKey.TangentOut, tangentScale, out var leftTangent);
|
||||
_accessor.GetTangent(ref rightKey.Value, ref rightKey.TangentIn, tangentScale, out var rightTangent);
|
||||
_accessor.Bezier(ref leftKey.Value, ref leftTangent, ref rightTangent, ref rightKey.Value, t, out result.Value);
|
||||
result.TangentIn = leftKey.TangentOut;
|
||||
result.TangentOut = rightKey.TangentIn;
|
||||
@@ -895,9 +955,9 @@ namespace FlaxEngine
|
||||
float t = Mathf.NearEqual(length, 0.0f) ? 0.0f : (time - leftKey.Time) / length;
|
||||
|
||||
// Evaluate the value at the curve
|
||||
float lengthThird = length / 3.0f;
|
||||
_accessor.GetTangent(ref leftKey.Value, ref leftKey.TangentOut, lengthThird, out var leftTangent);
|
||||
_accessor.GetTangent(ref rightKey.Value, ref rightKey.TangentIn, lengthThird, out var rightTangent);
|
||||
float tangentScale = length / 3.0f;
|
||||
_accessor.GetTangent(ref leftKey.Value, ref leftKey.TangentOut, tangentScale, out var leftTangent);
|
||||
_accessor.GetTangent(ref rightKey.Value, ref rightKey.TangentIn, tangentScale, out var rightTangent);
|
||||
_accessor.Bezier(ref leftKey.Value, ref leftTangent, ref rightTangent, ref rightKey.Value, t, out result);
|
||||
}
|
||||
|
||||
@@ -1000,5 +1060,29 @@ namespace FlaxEngine
|
||||
leftKey = Mathf.Max(0, start - 1);
|
||||
rightKey = Mathf.Min(start, Keyframes.Length - 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raw memory copy (used by scripting bindings - see MarshalAs tag).
|
||||
/// </summary>
|
||||
/// <param name="curve">The curve to copy.</param>
|
||||
/// <returns>The raw keyframes data.</returns>
|
||||
public static unsafe implicit operator byte[](BezierCurve<T> curve)
|
||||
{
|
||||
if (curve == null)
|
||||
return null;
|
||||
return MarshalKeyframes<Keyframe>(curve.Keyframes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raw memory copy (used by scripting bindings - see MarshalAs tag).
|
||||
/// </summary>
|
||||
/// <param name="raw">The raw keyframes data.</param>
|
||||
/// <returns>The curve.</returns>
|
||||
public static unsafe implicit operator BezierCurve<T>(byte[] raw)
|
||||
{
|
||||
if (raw == null || raw.Length == 0)
|
||||
return null;
|
||||
return new BezierCurve<T>(MarshalKeyframes<Keyframe>(raw));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,16 +247,18 @@ public:
|
||||
static void Interpolate(const BezierCurveKeyframe& a, const BezierCurveKeyframe& b, float alpha, float length, T& result)
|
||||
{
|
||||
T leftTangent, rightTangent;
|
||||
AnimationUtils::GetTangent(a.Value, a.TangentOut, length, leftTangent);
|
||||
AnimationUtils::GetTangent(b.Value, b.TangentIn, length, rightTangent);
|
||||
const float tangentScale = length / 3.0f;
|
||||
AnimationUtils::GetTangent(a.Value, a.TangentOut, tangentScale, leftTangent);
|
||||
AnimationUtils::GetTangent(b.Value, b.TangentIn, tangentScale, rightTangent);
|
||||
AnimationUtils::Bezier(a.Value, leftTangent, rightTangent, b.Value, alpha, result);
|
||||
}
|
||||
|
||||
static void InterpolateFirstDerivative(const BezierCurveKeyframe& a, const BezierCurveKeyframe& b, float alpha, float length, T& result)
|
||||
{
|
||||
T leftTangent, rightTangent;
|
||||
AnimationUtils::GetTangent(a.Value, a.TangentOut, length, leftTangent);
|
||||
AnimationUtils::GetTangent(b.Value, b.TangentIn, length, rightTangent);
|
||||
const float tangentScale = length / 3.0f;
|
||||
AnimationUtils::GetTangent(a.Value, a.TangentOut, tangentScale, leftTangent);
|
||||
AnimationUtils::GetTangent(b.Value, b.TangentIn, tangentScale, rightTangent);
|
||||
AnimationUtils::BezierFirstDerivative(a.Value, leftTangent, rightTangent, b.Value, alpha, result);
|
||||
}
|
||||
|
||||
@@ -264,8 +266,9 @@ public:
|
||||
{
|
||||
result.Time = a.Time + length * alpha;
|
||||
T leftTangent, rightTangent;
|
||||
AnimationUtils::GetTangent(a.Value, a.TangentOut, length, leftTangent);
|
||||
AnimationUtils::GetTangent(b.Value, b.TangentIn, length, rightTangent);
|
||||
const float tangentScale = length / 3.0f;
|
||||
AnimationUtils::GetTangent(a.Value, a.TangentOut, tangentScale, leftTangent);
|
||||
AnimationUtils::GetTangent(b.Value, b.TangentIn, tangentScale, rightTangent);
|
||||
AnimationUtils::Bezier(a.Value, leftTangent, rightTangent, b.Value, alpha, result.Value);
|
||||
result.TangentIn = a.TangentOut;
|
||||
result.TangentOut = b.TangentIn;
|
||||
@@ -498,7 +501,7 @@ protected:
|
||||
/// An animation spline represented by a set of keyframes, each representing an endpoint of a curve.
|
||||
/// </summary>
|
||||
template<class T, typename KeyFrame = LinearCurveKeyframe<T>>
|
||||
class Curve : public CurveBase<T, KeyFrame>
|
||||
API_CLASS(InBuild, Template, MarshalAs=Span<byte>) class Curve : public CurveBase<T, KeyFrame>
|
||||
{
|
||||
public:
|
||||
typedef CurveBase<T, KeyFrame> Base;
|
||||
@@ -760,28 +763,42 @@ public:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Raw memory copy (used by scripting bindings - see MarshalAs tag).
|
||||
Curve& operator=(const Span<byte>& raw)
|
||||
{
|
||||
ASSERT((raw.Length() % sizeof(KeyFrame)) == 0);
|
||||
const int32 count = raw.Length() / sizeof(KeyFrame);
|
||||
_keyframes.Resize(count, false);
|
||||
Platform::MemoryCopy(_keyframes.Get(), raw.Get(), sizeof(KeyFrame) * count);
|
||||
return *this;
|
||||
}
|
||||
operator Span<byte>()
|
||||
{
|
||||
return Span<byte>((const byte*)_keyframes.Get(), _keyframes.Count() * sizeof(KeyFrame));
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// An animation spline represented by a set of keyframes, each representing a value point.
|
||||
/// </summary>
|
||||
template<typename T>
|
||||
using StepCurve = Curve<T, StepCurveKeyframe<T>>;
|
||||
API_TYPEDEF() using StepCurve = Curve<T, StepCurveKeyframe<T>>;
|
||||
|
||||
/// <summary>
|
||||
/// An animation spline represented by a set of keyframes, each representing an endpoint of a linear curve.
|
||||
/// </summary>
|
||||
template<typename T>
|
||||
using LinearCurve = Curve<T, LinearCurveKeyframe<T>>;
|
||||
API_TYPEDEF() using LinearCurve = Curve<T, LinearCurveKeyframe<T>>;
|
||||
|
||||
/// <summary>
|
||||
/// An animation spline represented by a set of keyframes, each representing an endpoint of a cubic hermite curve.
|
||||
/// </summary>
|
||||
template<typename T>
|
||||
using HermiteCurve = Curve<T, HermiteCurveKeyframe<T>>;
|
||||
API_TYPEDEF() using HermiteCurve = Curve<T, HermiteCurveKeyframe<T>>;
|
||||
|
||||
/// <summary>
|
||||
/// An animation spline represented by a set of keyframes, each representing an endpoint of Bezier curve.
|
||||
/// </summary>
|
||||
template<typename T>
|
||||
using BezierCurve = Curve<T, BezierCurveKeyframe<T>>;
|
||||
API_TYPEDEF() using BezierCurve = Curve<T, BezierCurveKeyframe<T>>;
|
||||
|
||||
@@ -2263,6 +2263,14 @@ void VisualScript::GetMethodSignature(int32 index, String& name, byte& flags, St
|
||||
}
|
||||
}
|
||||
|
||||
Variant VisualScript::InvokeMethod(int32 index, const Variant& instance, Span<Variant> parameters) const
|
||||
{
|
||||
auto& method = _methods[index];
|
||||
Variant result;
|
||||
VisualScriptingModule.InvokeMethod((void*)&method, instance, parameters, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
Span<byte> VisualScript::GetMetaData(int32 typeID)
|
||||
{
|
||||
auto meta = Graph.Meta.GetEntry(typeID);
|
||||
|
||||
@@ -267,6 +267,9 @@ public:
|
||||
// Gets the signature data of the method.
|
||||
API_FUNCTION() void GetMethodSignature(int32 index, API_PARAM(Out) String& name, API_PARAM(Out) byte& flags, API_PARAM(Out) String& returnTypeName, API_PARAM(Out) Array<String>& paramNames, API_PARAM(Out) Array<String>& paramTypeNames, API_PARAM(Out) Array<bool>& paramOuts);
|
||||
|
||||
// Invokes the method.
|
||||
API_FUNCTION() Variant InvokeMethod(int32 index, const Variant& instance, Span<Variant> parameters) const;
|
||||
|
||||
// Gets the metadata of the script surface.
|
||||
API_FUNCTION() Span<byte> GetMetaData(int32 typeID);
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace FlaxEditor.Content.Settings
|
||||
{
|
||||
new BuildTarget
|
||||
{
|
||||
Name = "Windows 64bit",
|
||||
Output = "Output\\Win64",
|
||||
Name = "Windows",
|
||||
Output = "Output\\Windows",
|
||||
Platform = BuildPlatform.Windows64,
|
||||
Mode = BuildConfiguration.Development,
|
||||
},
|
||||
@@ -35,8 +35,8 @@ namespace FlaxEditor.Content.Settings
|
||||
{
|
||||
new BuildTarget
|
||||
{
|
||||
Name = "Windows 64bit",
|
||||
Output = "Output\\Win64",
|
||||
Name = "Windows",
|
||||
Output = "Output\\Windows",
|
||||
Platform = BuildPlatform.Windows64,
|
||||
Mode = BuildConfiguration.Release,
|
||||
},
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace FlaxEditor.Content.Settings
|
||||
public List<string> Tags = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// The layers names.
|
||||
/// The layer names.
|
||||
/// </summary>
|
||||
[EditorOrder(10), EditorDisplay("Layers", EditorDisplayAttribute.InlineStyle), Collection(CanResize = false, Display = CollectionAttribute.DisplayType.Inline)]
|
||||
public string[] Layers = new string[32];
|
||||
@@ -30,6 +30,31 @@ namespace FlaxEditor.Content.Settings
|
||||
return GetCurrentLayers(out int _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The layer names.
|
||||
/// </summary>
|
||||
[EditorOrder(10), EditorDisplay("Terrain Layers", EditorDisplayAttribute.InlineStyle), Collection(CanResize = false, Display = CollectionAttribute.DisplayType.Inline)]
|
||||
public string[] TerrainLayers = new string[8];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current terrain layer names. Returns "Layer" + index for layers without a name.
|
||||
/// </summary>
|
||||
/// <returns>The layer names.</returns>
|
||||
public static string[] GetCurrentTerrainLayers()
|
||||
{
|
||||
#if FLAX_TESTS
|
||||
return System.Array.Empty<string>();
|
||||
#else
|
||||
string[] layerNames = GameSettings.Load<LayersAndTagsSettings>().TerrainLayers;
|
||||
for (int i = 0; i < layerNames.Length; i++)
|
||||
{
|
||||
if (string.IsNullOrEmpty(layerNames[i]))
|
||||
layerNames[i] = $"Layer {i}";
|
||||
}
|
||||
return layerNames;
|
||||
#endif
|
||||
}
|
||||
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "LayersAndTagsSettingsInternal_GetCurrentLayers", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||
[return: MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "layerCount")]
|
||||
internal static partial string[] GetCurrentLayers(out int layerCount);
|
||||
|
||||
@@ -16,10 +16,14 @@
|
||||
#include <iostream>
|
||||
|
||||
#define LOG_ENABLE_FILE (!PLATFORM_SWITCH)
|
||||
#define LOG_ENABLE_WINDOWS_SINGLE_NEW_LINE_CHAR (PLATFORM_WINDOWS && PLATFORM_DESKTOP && (USE_EDITOR || !BUILD_RELEASE))
|
||||
|
||||
namespace
|
||||
{
|
||||
bool LogAfterInit = false, IsDuringLog = false;
|
||||
#if LOG_ENABLE_WINDOWS_SINGLE_NEW_LINE_CHAR
|
||||
bool IsWindowsSingleNewLineChar = false;
|
||||
#endif
|
||||
int LogTotalErrorsCnt = 0;
|
||||
FileWriteStream* LogFile = nullptr;
|
||||
CriticalSection LogLocker;
|
||||
@@ -86,6 +90,11 @@ bool Log::Logger::Init()
|
||||
}
|
||||
LogTotalErrorsCnt = 0;
|
||||
LogAfterInit = true;
|
||||
#if LOG_ENABLE_WINDOWS_SINGLE_NEW_LINE_CHAR
|
||||
String envVar;
|
||||
Platform::GetEnvironmentVariable(TEXT("GITHUB_ACTION"), envVar);
|
||||
IsWindowsSingleNewLineChar = envVar.HasChars();
|
||||
#endif
|
||||
|
||||
// Write BOM (UTF-16 (LE); BOM: FF FE)
|
||||
byte bom[] = { 0xFF, 0xFE };
|
||||
@@ -127,6 +136,11 @@ void Log::Logger::Write(const StringView& msg)
|
||||
printf("%s", ansi.Get());
|
||||
#else
|
||||
std::wcout.write(ptr, length);
|
||||
#if LOG_ENABLE_WINDOWS_SINGLE_NEW_LINE_CHAR
|
||||
if (IsWindowsSingleNewLineChar)
|
||||
std::wcout.write(TEXT("\n"), 1); // Github Actions show logs with duplicated new-line characters so skip \r
|
||||
else
|
||||
#endif
|
||||
std::wcout.write(TEXT(PLATFORM_LINE_TERMINATOR), ARRAY_COUNT(PLATFORM_LINE_TERMINATOR) - 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -124,9 +124,9 @@ void BoundingBox::Transform(const BoundingBox& box, const Matrix& matrix, Boundi
|
||||
const auto ya = up * box.Minimum.Y;
|
||||
const auto yb = up * box.Maximum.Y;
|
||||
|
||||
const auto backward = matrix.GetBackward();
|
||||
const auto za = backward * box.Minimum.Z;
|
||||
const auto zb = backward * box.Maximum.Z;
|
||||
const auto forward = matrix.GetForward();
|
||||
const auto za = forward * box.Minimum.Z;
|
||||
const auto zb = forward * box.Maximum.Z;
|
||||
|
||||
const auto translation = matrix.GetTranslation();
|
||||
const auto min = Vector3::Min(xa, xb) + Vector3::Min(ya, yb) + Vector3::Min(za, zb) + translation;
|
||||
@@ -146,9 +146,9 @@ void BoundingBox::Transform(const BoundingBox& box, const ::Transform& transform
|
||||
const auto ya = up * box.Minimum.Y;
|
||||
const auto yb = up * box.Maximum.Y;
|
||||
|
||||
const auto backward = Float3::Transform(Float3::Backward, transform.Orientation);
|
||||
const auto za = backward * box.Minimum.Z;
|
||||
const auto zb = backward * box.Maximum.Z;
|
||||
const auto forward = Float3::Transform(Float3::Forward, transform.Orientation);
|
||||
const auto za = forward * box.Minimum.Z;
|
||||
const auto zb = forward * box.Maximum.Z;
|
||||
|
||||
const auto min = Vector3::Min(xa, xb) + Vector3::Min(ya, yb) + Vector3::Min(za, zb) + transform.Translation;
|
||||
const auto max = Vector3::Max(xa, xb) + Vector3::Max(ya, yb) + Vector3::Max(za, zb) + transform.Translation;
|
||||
|
||||
@@ -474,9 +474,9 @@ namespace FlaxEngine
|
||||
var ya = up * box.Minimum.Y;
|
||||
var yb = up * box.Maximum.Y;
|
||||
|
||||
Double3 backward = transform.Backward;
|
||||
var za = backward * box.Minimum.Z;
|
||||
var zb = backward * box.Maximum.Z;
|
||||
Double3 forward = transform.Forward;
|
||||
var za = forward * box.Minimum.Z;
|
||||
var zb = forward * box.Maximum.Z;
|
||||
|
||||
var translation = transform.TranslationVector;
|
||||
var min = Vector3.Min(xa, xb) + Vector3.Min(ya, yb) + Vector3.Min(za, zb) + translation;
|
||||
@@ -514,9 +514,9 @@ namespace FlaxEngine
|
||||
var ya = up * box.Minimum.Y;
|
||||
var yb = up * box.Maximum.Y;
|
||||
|
||||
Double3 backward = transform.Backward;
|
||||
var za = backward * box.Minimum.Z;
|
||||
var zb = backward * box.Maximum.Z;
|
||||
Double3 forward = transform.Forward;
|
||||
var za = forward * box.Minimum.Z;
|
||||
var zb = forward * box.Maximum.Z;
|
||||
|
||||
var min = Vector3.Min(xa, xb) + Vector3.Min(ya, yb) + Vector3.Min(za, zb) + transform.Translation;
|
||||
var max = Vector3.Max(xa, xb) + Vector3.Max(ya, yb) + Vector3.Max(za, zb) + transform.Translation;
|
||||
|
||||
@@ -136,12 +136,12 @@ void Matrix::Decompose(Float3& scale, Matrix3x3& rotation, Float3& translation)
|
||||
const auto right = Float3::Cross(up, at);
|
||||
rotation.SetRight(right);
|
||||
rotation.SetUp(up);
|
||||
rotation.SetBackward(at);
|
||||
rotation.SetForward(at);
|
||||
|
||||
// In case of reflexions
|
||||
scale.X = Float3::Dot(right, GetRight()) > 0.0f ? scale.X : -scale.X;
|
||||
scale.Y = Float3::Dot(up, GetUp()) > 0.0f ? scale.Y : -scale.Y;
|
||||
scale.Z = Float3::Dot(at, GetBackward()) > 0.0f ? scale.Z : -scale.Z;
|
||||
scale.Z = Float3::Dot(at, GetForward()) > 0.0f ? scale.Z : -scale.Z;
|
||||
}
|
||||
|
||||
void Matrix::Decompose(Float3& scale, Matrix& rotation, Float3& translation) const
|
||||
|
||||
@@ -215,23 +215,9 @@ namespace FlaxEngine
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the forward <see cref="Float3" /> of the matrix; that is -M31, -M32, and -M33.
|
||||
/// Gets or sets the forward <see cref="Float3" /> of the matrix; that is M31, M32, and M33.
|
||||
/// </summary>
|
||||
public Float3 Forward
|
||||
{
|
||||
get => new Float3(-M31, -M32, -M33);
|
||||
set
|
||||
{
|
||||
M31 = -value.X;
|
||||
M32 = -value.Y;
|
||||
M33 = -value.Z;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the backward <see cref="Float3" /> of the matrix; that is M31, M32, and M33.
|
||||
/// </summary>
|
||||
public Float3 Backward
|
||||
{
|
||||
get => new Float3(M31, M32, M33);
|
||||
set
|
||||
@@ -242,6 +228,20 @@ namespace FlaxEngine
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the backward <see cref="Float3" /> of the matrix; that is -M31, -M32, and -M33.
|
||||
/// </summary>
|
||||
public Float3 Backward
|
||||
{
|
||||
get => new Float3(-M31, -M32, -M33);
|
||||
set
|
||||
{
|
||||
M31 = -value.X;
|
||||
M32 = -value.Y;
|
||||
M33 = -value.Z;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Matrix" /> struct.
|
||||
/// </summary>
|
||||
|
||||
@@ -210,31 +210,31 @@ public:
|
||||
// Gets the forward Float3 of the matrix; that is -M31, -M32, and -M33.
|
||||
Float3 GetForward() const
|
||||
{
|
||||
return -Float3(M31, M32, M33);
|
||||
return Float3(M31, M32, M33);
|
||||
}
|
||||
|
||||
// Sets the forward Float3 of the matrix; that is -M31, -M32, and -M33.
|
||||
void SetForward(const Float3& value)
|
||||
{
|
||||
M31 = -value.X;
|
||||
M32 = -value.Y;
|
||||
M33 = -value.Z;
|
||||
}
|
||||
|
||||
// Gets the backward Float3 of the matrix; that is M31, M32, and M33.
|
||||
Float3 GetBackward() const
|
||||
{
|
||||
return Float3(M31, M32, M33);
|
||||
}
|
||||
|
||||
// Sets the backward Float3 of the matrix; that is M31, M32, and M33.
|
||||
void SetBackward(const Float3& value)
|
||||
{
|
||||
M31 = value.X;
|
||||
M32 = value.Y;
|
||||
M33 = value.Z;
|
||||
}
|
||||
|
||||
// Gets the backward Float3 of the matrix; that is -M31, -M32, and -M33.
|
||||
Float3 GetBackward() const
|
||||
{
|
||||
return Float3(-M31, -M32, -M33);
|
||||
}
|
||||
|
||||
// Sets the backward Float3 of the matrix; that is -M31, -M32, and -M33.
|
||||
void SetBackward(const Float3& value)
|
||||
{
|
||||
M31 = -value.X;
|
||||
M32 = -value.Y;
|
||||
M33 = -value.Z;
|
||||
}
|
||||
|
||||
// Gets the first row in the matrix; that is M11, M12, M13, and M14.
|
||||
Float4 GetRow1() const
|
||||
{
|
||||
|
||||
@@ -225,7 +225,7 @@ void Matrix3x3::Decompose(Float3& scale, Matrix3x3& rotation) const
|
||||
const auto right = Float3::Cross(up, at);
|
||||
rotation.SetRight(right);
|
||||
rotation.SetUp(up);
|
||||
rotation.SetBackward(at);
|
||||
rotation.SetForward(at);
|
||||
|
||||
// In case of reflexions
|
||||
scale.X = Float3::Dot(right, GetRight()) > 0.0f ? scale.X : -scale.X;
|
||||
|
||||
@@ -303,9 +303,6 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is an identity Matrix3x3.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is an identity Matrix3x3; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsIdentity => Equals(Identity);
|
||||
|
||||
/// <summary>
|
||||
@@ -566,19 +563,19 @@ namespace FlaxEngine
|
||||
/// </remarks>
|
||||
public bool DecomposeUniformScale(out float scale, out Quaternion rotation)
|
||||
{
|
||||
//Scaling is the length of the rows. ( just take one row since this is a uniform matrix)
|
||||
// Scaling is the length of the rows. ( just take one row since this is a uniform matrix)
|
||||
scale = (float)Math.Sqrt((M11 * M11) + (M12 * M12) + (M13 * M13));
|
||||
var invScale = 1f / scale;
|
||||
|
||||
//If any of the scaling factors are zero, then the rotation matrix can not exist.
|
||||
// If any of the scaling factors are zero, then the rotation matrix can not exist
|
||||
if (Math.Abs(scale) < Mathf.Epsilon)
|
||||
{
|
||||
rotation = Quaternion.Identity;
|
||||
return false;
|
||||
}
|
||||
|
||||
//The rotation is the left over matrix after dividing out the scaling.
|
||||
Matrix3x3 rotationmatrix = new Matrix3x3
|
||||
// The rotation is the leftover matrix after dividing out the scaling
|
||||
var rotationMatrix = new Matrix3x3
|
||||
{
|
||||
M11 = M11 * invScale,
|
||||
M12 = M12 * invScale,
|
||||
@@ -590,8 +587,7 @@ namespace FlaxEngine
|
||||
M32 = M32 * invScale,
|
||||
M33 = M33 * invScale
|
||||
};
|
||||
|
||||
Quaternion.RotationMatrix(ref rotationmatrix, out rotation);
|
||||
Quaternion.RotationMatrix(ref rotationMatrix, out rotation);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -175,34 +175,34 @@ public:
|
||||
M13 = -value.Z;
|
||||
}
|
||||
|
||||
// Gets the forward Float3 of the matrix; that is -M31, -M32, and -M33.
|
||||
// Gets the forward Float3 of the matrix; that is M31, M32, and M33.
|
||||
Float3 GetForward() const
|
||||
{
|
||||
return -Float3(M31, M32, M33);
|
||||
}
|
||||
|
||||
// Sets the forward Float3 of the matrix; that is -M31, -M32, and -M33.
|
||||
// Sets the forward Float3 of the matrix; that is M31, M32, and M33.
|
||||
void SetForward(const Float3& value)
|
||||
{
|
||||
M31 = -value.X;
|
||||
M32 = -value.Y;
|
||||
M33 = -value.Z;
|
||||
}
|
||||
|
||||
// Gets the backward Float3 of the matrix; that is M31, M32, and M33.
|
||||
Float3 GetBackward() const
|
||||
{
|
||||
return Float3(M31, M32, M33);
|
||||
}
|
||||
|
||||
// Sets the backward Float3 of the matrix; that is M31, M32, and M33.
|
||||
void SetBackward(const Float3& value)
|
||||
{
|
||||
M31 = value.X;
|
||||
M32 = value.Y;
|
||||
M33 = value.Z;
|
||||
}
|
||||
|
||||
// Gets the backward Float3 of the matrix; that is -M31, -M32, and -M33.
|
||||
Float3 GetBackward() const
|
||||
{
|
||||
return Float3(-M31, -M32, -M33);
|
||||
}
|
||||
|
||||
// Sets the backward Float3 of the matrix; that is -M31, -M32, and -M33.
|
||||
void SetBackward(const Float3& value)
|
||||
{
|
||||
M31 = -value.X;
|
||||
M32 = -value.Y;
|
||||
M33 = -value.Z;
|
||||
}
|
||||
|
||||
// Gets the first row in the matrix; that is M11, M12 and M13.
|
||||
Float3 GetRow1() const
|
||||
{
|
||||
|
||||
@@ -1827,6 +1827,7 @@ Variant::operator Float4() const
|
||||
return Float4(*(Float3*)AsData, 0.0f);
|
||||
case VariantType::Float4:
|
||||
case VariantType::Color:
|
||||
case VariantType::Quaternion:
|
||||
return *(Float4*)AsData;
|
||||
case VariantType::Double2:
|
||||
return Float4(AsDouble2(), 0.0f, 0.0f);
|
||||
|
||||
@@ -94,6 +94,13 @@ struct DebugLine
|
||||
float TimeLeft;
|
||||
};
|
||||
|
||||
struct DebugGeometryBuffer
|
||||
{
|
||||
GPUBuffer* Buffer;
|
||||
float TimeLeft;
|
||||
Matrix Transform;
|
||||
};
|
||||
|
||||
struct DebugTriangle
|
||||
{
|
||||
Float3 V0;
|
||||
@@ -122,12 +129,9 @@ struct DebugText3D
|
||||
float TimeLeft;
|
||||
};
|
||||
|
||||
PACK_STRUCT(struct Vertex {
|
||||
Float3 Position;
|
||||
Color32 Color;
|
||||
});
|
||||
typedef DebugDraw::Vertex Vertex;
|
||||
|
||||
GPU_CB_STRUCT(Data {
|
||||
GPU_CB_STRUCT(ShaderData {
|
||||
Matrix ViewProjection;
|
||||
Float2 Padding;
|
||||
float ClipPosZBias;
|
||||
@@ -231,6 +235,7 @@ void TeleportList(const Float3& delta, Array<DebugText3D>& list)
|
||||
|
||||
struct DebugDrawData
|
||||
{
|
||||
Array<DebugGeometryBuffer> GeometryBuffers;
|
||||
Array<DebugLine> DefaultLines;
|
||||
Array<Vertex> OneFrameLines;
|
||||
Array<DebugTriangle> DefaultTriangles;
|
||||
@@ -244,7 +249,7 @@ struct DebugDrawData
|
||||
|
||||
inline int32 Count() const
|
||||
{
|
||||
return LinesCount() + TrianglesCount() + TextCount();
|
||||
return LinesCount() + TrianglesCount() + TextCount() + GeometryBuffers.Count();
|
||||
}
|
||||
|
||||
inline int32 LinesCount() const
|
||||
@@ -280,6 +285,7 @@ struct DebugDrawData
|
||||
|
||||
inline void Update(float deltaTime)
|
||||
{
|
||||
UpdateList(deltaTime, GeometryBuffers);
|
||||
UpdateList(deltaTime, DefaultLines);
|
||||
UpdateList(deltaTime, DefaultTriangles);
|
||||
UpdateList(deltaTime, DefaultWireTriangles);
|
||||
@@ -784,7 +790,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
|
||||
// Update constant buffer
|
||||
const auto cb = DebugDrawShader->GetShader()->GetCB(0);
|
||||
Data data;
|
||||
ShaderData data;
|
||||
Matrix vp;
|
||||
Matrix::Multiply(view.View, view.Projection, vp);
|
||||
Matrix::Transpose(vp, data.ViewProjection);
|
||||
@@ -830,6 +836,22 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
context->Draw(depthTestTriangles.StartVertex, depthTestTriangles.VertexCount);
|
||||
}
|
||||
|
||||
// Geometries
|
||||
for (auto& geometry : Context->DebugDrawDepthTest.GeometryBuffers)
|
||||
{
|
||||
auto tmp = data;
|
||||
Matrix mvp;
|
||||
Matrix::Multiply(geometry.Transform, vp, mvp);
|
||||
Matrix::Transpose(mvp, tmp.ViewProjection);
|
||||
context->UpdateCB(cb, &tmp);
|
||||
auto state = data.EnableDepthTest ? &DebugDrawPsLinesDepthTest : &DebugDrawPsLinesDefault;
|
||||
context->SetState(state->Get(enableDepthWrite, true));
|
||||
context->BindVB(ToSpan(&geometry.Buffer, 1));
|
||||
context->Draw(0, geometry.Buffer->GetElementsCount());
|
||||
}
|
||||
if (Context->DebugDrawDepthTest.GeometryBuffers.HasItems())
|
||||
context->UpdateCB(cb, &data);
|
||||
|
||||
if (data.EnableDepthTest)
|
||||
context->UnBindSR(0);
|
||||
}
|
||||
@@ -862,6 +884,19 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe
|
||||
context->BindVB(ToSpan(&vb, 1));
|
||||
context->Draw(defaultTriangles.StartVertex, defaultTriangles.VertexCount);
|
||||
}
|
||||
|
||||
// Geometries
|
||||
for (auto& geometry : Context->DebugDrawDefault.GeometryBuffers)
|
||||
{
|
||||
auto tmp = data;
|
||||
Matrix mvp;
|
||||
Matrix::Multiply(geometry.Transform, vp, mvp);
|
||||
Matrix::Transpose(mvp, tmp.ViewProjection);
|
||||
context->UpdateCB(cb, &tmp);
|
||||
context->SetState(DebugDrawPsLinesDefault.Get(false, false));
|
||||
context->BindVB(ToSpan(&geometry.Buffer, 1));
|
||||
context->Draw(0, geometry.Buffer->GetElementsCount());
|
||||
}
|
||||
}
|
||||
|
||||
// Text
|
||||
@@ -1088,6 +1123,24 @@ void DebugDraw::DrawLines(const Span<Float3>& lines, const Matrix& transform, co
|
||||
}
|
||||
}
|
||||
|
||||
void DebugDraw::DrawLines(GPUBuffer* lines, const Matrix& transform, float duration, bool depthTest)
|
||||
{
|
||||
if (lines == nullptr || lines->GetSize() == 0)
|
||||
return;
|
||||
if (lines->GetSize() % (sizeof(Vertex) * 2) != 0)
|
||||
{
|
||||
DebugLog::ThrowException("Cannot draw debug lines with uneven amount of items in array");
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw lines
|
||||
auto& debugDrawData = depthTest ? Context->DebugDrawDepthTest : Context->DebugDrawDefault;
|
||||
auto& geometry = debugDrawData.GeometryBuffers.AddOne();
|
||||
geometry.Buffer = lines;
|
||||
geometry.TimeLeft = duration;
|
||||
geometry.Transform = transform * Matrix::Translation(-Context->Origin);
|
||||
}
|
||||
|
||||
void DebugDraw::DrawLines(const Array<Float3>& lines, const Matrix& transform, const Color& color, float duration, bool depthTest)
|
||||
{
|
||||
DrawLines(Span<Float3>(lines.Get(), lines.Count()), transform, color, duration, depthTest);
|
||||
@@ -2147,6 +2200,7 @@ void DebugDraw::DrawText(const StringView& text, const Transform& transform, con
|
||||
|
||||
void DebugDraw::Clear(void* context)
|
||||
{
|
||||
DebugDraw::UpdateContext(context, MAX_float);
|
||||
UpdateContext(context, MAX_float);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
#include "Engine/Core/Math/Color.h"
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
#include "Engine/Core/Math/Vector3.h"
|
||||
#include "Engine/Core/Types/Span.h"
|
||||
|
||||
struct RenderView;
|
||||
@@ -14,6 +16,7 @@ class Light;
|
||||
struct RenderContext;
|
||||
class GPUTextureView;
|
||||
class GPUContext;
|
||||
class GPUBuffer;
|
||||
class RenderTask;
|
||||
class SceneRenderTask;
|
||||
class Actor;
|
||||
@@ -26,6 +29,14 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(DebugDraw);
|
||||
|
||||
/// <summary>
|
||||
/// Vertex data for debug shapes.
|
||||
/// </summary>
|
||||
PACK_STRUCT(struct Vertex {
|
||||
Float3 Position;
|
||||
Color32 Color;
|
||||
});
|
||||
|
||||
#if USE_EDITOR
|
||||
/// <summary>
|
||||
/// Allocates the context for Debug Drawing. Can be use to redirect debug shapes collecting to a separate container (instead of global state).
|
||||
@@ -175,6 +186,15 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
API_FUNCTION() static void DrawLines(const Span<Float3>& lines, const Matrix& transform, const Color& color = Color::White, float duration = 0.0f, bool depthTest = true);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the lines using the provided vertex buffer that contains pairs of Vertex elements. Line positions are located one after another (e.g. l0.start, l0.end, l1.start, l1.end,...).
|
||||
/// </summary>
|
||||
/// <param name="lines">The GPU buffer with vertices for lines (must have multiple of 2 elements).</param>
|
||||
/// <param name="transform">The custom matrix used to transform all line vertices.</param>
|
||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||
API_FUNCTION() static void DrawLines(GPUBuffer* lines, const Matrix& transform, float duration = 0.0f, bool depthTest = true);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the lines. Line positions are located one after another (e.g. l0.start, l0.end, l1.start, l1.end,...).
|
||||
/// </summary>
|
||||
@@ -691,9 +711,9 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
||||
API_FUNCTION() static void DrawText(const StringView& text, const Transform& transform, const Color& color = Color::White, int32 size = 32, float duration = 0.0f);
|
||||
|
||||
/// <summary>
|
||||
/// Clear all debug draw displayed on sceen.
|
||||
/// Clears all debug shapes displayed on screen.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <param name="context">The context.</param>
|
||||
API_FUNCTION() static void Clear(void* context = nullptr);
|
||||
};
|
||||
|
||||
|
||||
@@ -154,6 +154,7 @@ bool CommandLine::Parse(const Char* cmdLine)
|
||||
PARSE_ARG_SWITCH("-build ", Build);
|
||||
PARSE_BOOL_SWITCH("-skipcompile ", SkipCompile);
|
||||
PARSE_BOOL_SWITCH("-shaderdebug ", ShaderDebug);
|
||||
PARSE_BOOL_SWITCH("-exit ", Exit);
|
||||
PARSE_ARG_OPT_SWITCH("-play ", Play);
|
||||
#endif
|
||||
#if USE_EDITOR || !BUILD_RELEASE
|
||||
|
||||
@@ -168,6 +168,11 @@ public:
|
||||
/// </summary>
|
||||
Nullable<bool> ShaderDebug;
|
||||
|
||||
/// <summary>
|
||||
/// -exit (exits the editor after startup and performing all queued actions). Usefull when invoking editor from CL/CD.
|
||||
/// </summary>
|
||||
Nullable<bool> Exit;
|
||||
|
||||
/// <summary>
|
||||
/// -play !guid! ( Scene to play, can be empty to use default )
|
||||
/// </summary>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
|
||||
#define GPU_TASKS_USE_DEDICATED_CONTEXT 0
|
||||
|
||||
@@ -36,7 +37,8 @@ GPUTasksContext::~GPUTasksContext()
|
||||
auto task = tasks[i];
|
||||
if (task->GetSyncPoint() <= _currentSyncPoint && task->GetState() != TaskState::Finished)
|
||||
{
|
||||
LOG(Warning, "{0} has been canceled before a sync", task->ToString());
|
||||
if (!Globals::IsRequestingExit)
|
||||
LOG(Warning, "{0} has been canceled before a sync", task->ToString());
|
||||
task->CancelSync();
|
||||
}
|
||||
}
|
||||
@@ -60,7 +62,8 @@ void GPUTasksContext::OnCancelSync(GPUTask* task)
|
||||
|
||||
_tasksDone.Remove(task);
|
||||
|
||||
LOG(Warning, "{0} has been canceled before a sync", task->ToString());
|
||||
if (!Globals::IsRequestingExit)
|
||||
LOG(Warning, "{0} has been canceled before a sync", task->ToString());
|
||||
}
|
||||
|
||||
void GPUTasksContext::OnFrameBegin()
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "GPUResourceProperty.h"
|
||||
#include "GPUBufferDescription.h"
|
||||
#include "PixelFormatExtensions.h"
|
||||
#include "RenderTask.h"
|
||||
#include "Async/Tasks/GPUCopyResourceTask.h"
|
||||
#include "Engine/Core/Utilities.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
@@ -358,6 +359,16 @@ void GPUBuffer::SetData(const void* data, uint32 size)
|
||||
Log::ArgumentOutOfRangeException(TEXT("Buffer.SetData"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_desc.Usage == GPUResourceUsage::Default && GPUDevice::Instance->IsRendering())
|
||||
{
|
||||
// Upload using the context (will use internal staging buffer inside command buffer)
|
||||
RenderContext::GPULocker.Lock();
|
||||
GPUDevice::Instance->GetMainContext()->UpdateBuffer(this, data, size);
|
||||
RenderContext::GPULocker.Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
void* mapped = Map(GPUResourceMapMode::Write);
|
||||
if (!mapped)
|
||||
return;
|
||||
|
||||
@@ -74,8 +74,7 @@ public:
|
||||
/// </summary>
|
||||
API_PROPERTY() FORCE_INLINE uint32 GetElementsCount() const
|
||||
{
|
||||
ASSERT(_desc.Stride > 0);
|
||||
return _desc.Size / _desc.Stride;
|
||||
return _desc.Stride > 0 ? _desc.Size / _desc.Stride : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -282,35 +282,35 @@ void MaterialParameter::Bind(BindMeta& meta) const
|
||||
switch (_type)
|
||||
{
|
||||
case MaterialParameterType::Bool:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(bool));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(bool)));
|
||||
*((int32*)(meta.Constants.Get() + _offset)) = _asBool;
|
||||
break;
|
||||
case MaterialParameterType::Integer:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(int32));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(int32)));
|
||||
*((int32*)(meta.Constants.Get() + _offset)) = _asInteger;
|
||||
break;
|
||||
case MaterialParameterType::Float:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(float));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(float)));
|
||||
*((float*)(meta.Constants.Get() + _offset)) = _asFloat;
|
||||
break;
|
||||
case MaterialParameterType::Vector2:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Float2));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(Float2)));
|
||||
*((Float2*)(meta.Constants.Get() + _offset)) = _asVector2;
|
||||
break;
|
||||
case MaterialParameterType::Vector3:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Float3));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(Float3)));
|
||||
*((Float3*)(meta.Constants.Get() + _offset)) = _asVector3;
|
||||
break;
|
||||
case MaterialParameterType::Vector4:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Float4));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(Float4)));
|
||||
*((Float4*)(meta.Constants.Get() + _offset)) = *(Float4*)&AsData;
|
||||
break;
|
||||
case MaterialParameterType::Color:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Float4));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(Float4)));
|
||||
*((Color*)(meta.Constants.Get() + _offset)) = _asColor;
|
||||
break;
|
||||
case MaterialParameterType::Matrix:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Matrix));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(Matrix)));
|
||||
Matrix::Transpose(*(Matrix*)&AsData, *(Matrix*)(meta.Constants.Get() + _offset));
|
||||
break;
|
||||
case MaterialParameterType::NormalMap:
|
||||
@@ -409,44 +409,44 @@ void MaterialParameter::Bind(BindMeta& meta) const
|
||||
switch (e->Value.Type.Type)
|
||||
{
|
||||
case VariantType::Bool:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(bool));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(bool)));
|
||||
*((bool*)(meta.Constants.Get() + _offset)) = e->Value.AsBool;
|
||||
break;
|
||||
case VariantType::Int:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(int32));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(int32)));
|
||||
*((int32*)(meta.Constants.Get() + _offset)) = e->Value.AsInt;
|
||||
break;
|
||||
case VariantType::Uint:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(uint32));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(uint32)));
|
||||
*((uint32*)(meta.Constants.Get() + _offset)) = e->Value.AsUint;
|
||||
break;
|
||||
case VariantType::Float:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(float));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(float)));
|
||||
*((float*)(meta.Constants.Get() + _offset)) = e->Value.AsFloat;
|
||||
break;
|
||||
case VariantType::Float2:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Float2));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(Float2)));
|
||||
*((Float2*)(meta.Constants.Get() + _offset)) = e->Value.AsFloat2();
|
||||
break;
|
||||
case VariantType::Float3:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Float3));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(Float3)));
|
||||
*((Float3*)(meta.Constants.Get() + _offset)) = e->Value.AsFloat3();
|
||||
break;
|
||||
case VariantType::Float4:
|
||||
case VariantType::Color:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Float4));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(Float4)));
|
||||
*((Float4*)(meta.Constants.Get() + _offset)) = e->Value.AsFloat4();
|
||||
break;
|
||||
case VariantType::Double2:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Float2));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(Float2)));
|
||||
*((Float2*)(meta.Constants.Get() + _offset)) = (Float2)e->Value.AsDouble2();
|
||||
break;
|
||||
case VariantType::Double3:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Float3));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(Float3)));
|
||||
*((Float3*)(meta.Constants.Get() + _offset)) = (Float3)e->Value.AsDouble3();
|
||||
break;
|
||||
case VariantType::Double4:
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)_offset + sizeof(Float4));
|
||||
ASSERT_LOW_LAYER(meta.Constants.Get() && meta.Constants.Length() >= (int32)(_offset + sizeof(Float4)));
|
||||
*((Float4*)(meta.Constants.Get() + _offset)) = (Float4)e->Value.AsDouble4();
|
||||
break;
|
||||
default: ;
|
||||
|
||||
@@ -85,7 +85,7 @@ void ParticleMaterialShader::Bind(BindParameters& params)
|
||||
{
|
||||
const StringView name(param.GetName().Get() + 9, param.GetName().Length() - 9);
|
||||
const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name);
|
||||
ASSERT_LOW_LAYER(bindMeta.Constants.Get() && bindMeta.Constants.Length() >= (int32)param.GetBindOffset() + sizeof(int32));
|
||||
ASSERT_LOW_LAYER(bindMeta.Constants.Get() && bindMeta.Constants.Length() >= (int32)(param.GetBindOffset() + sizeof(int32)));
|
||||
*((int32*)(bindMeta.Constants.Get() + param.GetBindOffset())) = offset;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ void VolumeParticleMaterialShader::Bind(BindParameters& params)
|
||||
{
|
||||
const StringView name(param.GetName().Get() + 9, param.GetName().Length() - 9);
|
||||
const int32 offset = drawCall.Particle.Particles->Layout->FindAttributeOffset(name);
|
||||
ASSERT_LOW_LAYER(bindMeta.Constants.Get() && bindMeta.Constants.Length() >= (int32)param.GetBindOffset() + sizeof(int32));
|
||||
ASSERT_LOW_LAYER(bindMeta.Constants.Get() && bindMeta.Constants.Length() >= (int32)(param.GetBindOffset() + sizeof(int32)));
|
||||
*((int32*)(bindMeta.Constants.Get() + param.GetBindOffset())) = offset;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,7 +285,10 @@ void GPUContextDX11::SetBlendFactor(const Float4& value)
|
||||
void GPUContextDX11::SetStencilRef(uint32 value)
|
||||
{
|
||||
if (CurrentStencilRef != value)
|
||||
{
|
||||
CurrentStencilRef = value;
|
||||
_context->OMSetDepthStencilState(CurrentDepthStencilState, CurrentStencilRef);
|
||||
}
|
||||
}
|
||||
|
||||
void GPUContextDX11::ResetSR()
|
||||
|
||||
@@ -158,10 +158,10 @@ float Spline::GetSplineLength() const
|
||||
const auto& b = Curve[i];
|
||||
Vector3 prevPoint = a.Value.Translation * scale;
|
||||
|
||||
const float length = Math::Abs(b.Time - a.Time);
|
||||
const float tangentScale = Math::Abs(b.Time - a.Time) / 3.0f;
|
||||
Vector3 leftTangent, rightTangent;
|
||||
AnimationUtils::GetTangent(a.Value.Translation, a.TangentOut.Translation, length, leftTangent);
|
||||
AnimationUtils::GetTangent(b.Value.Translation, b.TangentIn.Translation, length, rightTangent);
|
||||
AnimationUtils::GetTangent(a.Value.Translation, a.TangentOut.Translation, tangentScale, leftTangent);
|
||||
AnimationUtils::GetTangent(b.Value.Translation, b.TangentIn.Translation, tangentScale, rightTangent);
|
||||
|
||||
for (int32 slice = 1; slice < slices; slice++)
|
||||
{
|
||||
@@ -189,10 +189,10 @@ float Spline::GetSplineSegmentLength(int32 index) const
|
||||
const Vector3 scale = _transform.Scale;
|
||||
Vector3 prevPoint = a.Value.Translation * scale;
|
||||
{
|
||||
const float length = Math::Abs(b.Time - a.Time);
|
||||
const float tangentScale = Math::Abs(b.Time - a.Time) / 3.0f;
|
||||
Vector3 leftTangent, rightTangent;
|
||||
AnimationUtils::GetTangent(a.Value.Translation, a.TangentOut.Translation, length, leftTangent);
|
||||
AnimationUtils::GetTangent(b.Value.Translation, b.TangentIn.Translation, length, rightTangent);
|
||||
AnimationUtils::GetTangent(a.Value.Translation, a.TangentOut.Translation, tangentScale, leftTangent);
|
||||
AnimationUtils::GetTangent(b.Value.Translation, b.TangentIn.Translation, tangentScale, rightTangent);
|
||||
|
||||
for (int32 slice = 1; slice < slices; slice++)
|
||||
{
|
||||
@@ -478,9 +478,7 @@ void Spline::GetKeyframes(MArray* data)
|
||||
|
||||
void Spline::SetKeyframes(MArray* data)
|
||||
{
|
||||
const int32 count = MCore::Array::GetLength(data);
|
||||
Curve.GetKeyframes().Resize(count, false);
|
||||
Platform::MemoryCopy(Curve.GetKeyframes().Get(), MCore::Array::GetAddress(data), sizeof(Keyframe) * count);
|
||||
Curve = Span<byte>((const byte*)MCore::Array::GetAddress(data), MCore::Array::GetLength(data));
|
||||
UpdateSpline();
|
||||
}
|
||||
|
||||
|
||||
@@ -184,9 +184,9 @@ void SplineModel::OnSplineUpdated()
|
||||
auto& instance = _instances[segment];
|
||||
const auto& start = keyframes[segment];
|
||||
const auto& end = keyframes[segment + 1];
|
||||
const float length = end.Time - start.Time;
|
||||
AnimationUtils::GetTangent(start.Value, start.TangentOut, length, leftTangent);
|
||||
AnimationUtils::GetTangent(end.Value, end.TangentIn, length, rightTangent);
|
||||
const float tangentScale = (end.Time - start.Time) / 3.0f;
|
||||
AnimationUtils::GetTangent(start.Value, start.TangentOut, tangentScale, leftTangent);
|
||||
AnimationUtils::GetTangent(end.Value, end.TangentIn, tangentScale, rightTangent);
|
||||
|
||||
// Find maximum scale over the segment spline and collect the segment positions for bounds
|
||||
segmentPoints.Clear();
|
||||
@@ -256,9 +256,9 @@ void SplineModel::UpdateDeformationBuffer()
|
||||
auto& instance = _instances[segment];
|
||||
const auto& start = keyframes[segment];
|
||||
const auto& end = keyframes[segment + 1];
|
||||
const float length = end.Time - start.Time;
|
||||
AnimationUtils::GetTangent(start.Value, start.TangentOut, length, leftTangent);
|
||||
AnimationUtils::GetTangent(end.Value, end.TangentIn, length, rightTangent);
|
||||
const float tangentScale = (end.Time - start.Time) / 3.0f;
|
||||
AnimationUtils::GetTangent(start.Value, start.TangentOut, tangentScale, leftTangent);
|
||||
AnimationUtils::GetTangent(end.Value, end.TangentIn, tangentScale, rightTangent);
|
||||
for (int32 chunk = 0; chunk < chunksPerSegment; chunk++)
|
||||
{
|
||||
const float alpha = (chunk == chunksPerSegment - 1) ? 1.0f : ((float)chunk * chunksPerSegmentInv);
|
||||
@@ -291,10 +291,10 @@ void SplineModel::UpdateDeformationBuffer()
|
||||
{
|
||||
const auto& start = keyframes[segments - 1];
|
||||
const auto& end = keyframes[segments];
|
||||
const float length = end.Time - start.Time;
|
||||
const float tangentScale = (end.Time - start.Time) / 3.0f;
|
||||
const float alpha = 1.0f - ZeroTolerance; // Offset to prevent zero derivative at the end of the curve
|
||||
AnimationUtils::GetTangent(start.Value, start.TangentOut, length, leftTangent);
|
||||
AnimationUtils::GetTangent(end.Value, end.TangentIn, length, rightTangent);
|
||||
AnimationUtils::GetTangent(start.Value, start.TangentOut, tangentScale, leftTangent);
|
||||
AnimationUtils::GetTangent(end.Value, end.TangentIn, tangentScale, rightTangent);
|
||||
AnimationUtils::Bezier(start.Value, leftTangent, rightTangent, end.Value, alpha, transform);
|
||||
Vector3 direction;
|
||||
AnimationUtils::BezierFirstDerivative(start.Value.Translation, leftTangent.Translation, rightTangent.Translation, end.Value.Translation, alpha, direction);
|
||||
|
||||
@@ -90,6 +90,7 @@ void SceneRendering::Draw(RenderContextBatch& renderContextBatch, DrawCategory c
|
||||
// Draw physics shapes
|
||||
if (EnumHasAnyFlags(view.Flags, ViewFlags::PhysicsDebug) || view.Mode == ViewMode::PhysicsColliders)
|
||||
{
|
||||
PROFILE_CPU_NAMED("PhysicsDebug");
|
||||
const PhysicsDebugCallback* physicsDebugData = PhysicsDebug.Get();
|
||||
for (int32 i = 0; i < PhysicsDebug.Count(); i++)
|
||||
{
|
||||
@@ -100,6 +101,7 @@ void SceneRendering::Draw(RenderContextBatch& renderContextBatch, DrawCategory c
|
||||
// Draw light shapes
|
||||
if (EnumHasAnyFlags(view.Flags, ViewFlags::LightsDebug))
|
||||
{
|
||||
PROFILE_CPU_NAMED("LightsDebug");
|
||||
const LightsDebugCallback* lightsDebugData = LightsDebug.Get();
|
||||
for (int32 i = 0; i < LightsDebug.Count(); i++)
|
||||
{
|
||||
|
||||
@@ -456,6 +456,7 @@ void ParticleEmitterGPUGenerator::PrepareGraph(ParticleEmitterGraphGPU* graph)
|
||||
mp.AsFloat3 = param->Value.AsFloat3();
|
||||
break;
|
||||
case VariantType::Float4:
|
||||
case VariantType::Quaternion:
|
||||
mp.Type = MaterialParameterType::Vector4;
|
||||
*(Float4*)&mp.AsData = param->Value.AsFloat4();
|
||||
break;
|
||||
|
||||
@@ -214,9 +214,9 @@ void SplineCollider::GetGeometry(CollisionShape& collision)
|
||||
auto offsetIndices = segment * collisionIndices.Count();
|
||||
const auto& start = keyframes[segment];
|
||||
const auto& end = keyframes[segment + 1];
|
||||
const float length = end.Time - start.Time;
|
||||
AnimationUtils::GetTangent(start.Value, start.TangentOut, length, leftTangent);
|
||||
AnimationUtils::GetTangent(end.Value, end.TangentIn, length, rightTangent);
|
||||
const float tangentScale = (end.Time - start.Time) / 3.0f;
|
||||
AnimationUtils::GetTangent(start.Value, start.TangentOut, tangentScale, leftTangent);
|
||||
AnimationUtils::GetTangent(end.Value, end.TangentIn, tangentScale, rightTangent);
|
||||
|
||||
// Vertex buffer is deformed along the spline
|
||||
auto srcVertices = collisionVertices.Get();
|
||||
|
||||
@@ -468,12 +468,12 @@ int32 MacPlatform::CreateProcess(CreateProcessSettings& settings)
|
||||
if (settings.WaitForEnd)
|
||||
{
|
||||
id<NSObject> outputObserver = nil;
|
||||
id<NSObject> outputObserverError = nil;
|
||||
|
||||
if (captureStdOut)
|
||||
{
|
||||
NSPipe *stdoutPipe = [NSPipe pipe];
|
||||
NSPipe* stdoutPipe = [NSPipe pipe];
|
||||
[task setStandardOutput:stdoutPipe];
|
||||
|
||||
outputObserver = [[NSNotificationCenter defaultCenter]
|
||||
addObserverForName: NSFileHandleDataAvailableNotification
|
||||
object: [stdoutPipe fileHandleForReading]
|
||||
@@ -497,8 +497,34 @@ int32 MacPlatform::CreateProcess(CreateProcessSettings& settings)
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
[[stdoutPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
|
||||
|
||||
NSPipe *stderrPipe = [NSPipe pipe];
|
||||
[task setStandardError:stderrPipe];
|
||||
outputObserverError = [[NSNotificationCenter defaultCenter]
|
||||
addObserverForName: NSFileHandleDataAvailableNotification
|
||||
object: [stderrPipe fileHandleForReading]
|
||||
queue: nil
|
||||
usingBlock:^(NSNotification* notification)
|
||||
{
|
||||
NSData* data = [stderrPipe fileHandleForReading].availableData;
|
||||
if (data.length)
|
||||
{
|
||||
String line((const char*)data.bytes, data.length);
|
||||
if (settings.SaveOutput)
|
||||
settings.Output.Add(line.Get(), line.Length());
|
||||
if (settings.LogOutput)
|
||||
{
|
||||
StringView lineView(line);
|
||||
if (line[line.Length() - 1] == '\n')
|
||||
lineView = StringView(line.Get(), line.Length() - 1);
|
||||
Log::Logger::Write(LogType::Error, lineView);
|
||||
}
|
||||
[[stderrPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
|
||||
}
|
||||
}
|
||||
];
|
||||
[[stderrPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
|
||||
}
|
||||
|
||||
String exception;
|
||||
|
||||
@@ -301,12 +301,12 @@ void WriteTri(const Float2& p0, const Float2& p1, const Float2& p2, const Float2
|
||||
IBIndex += 3;
|
||||
}
|
||||
|
||||
void WriteTri(const Float2& p0, const Float2& p1, const Float2& p2, const Color& color0, const Color& color1, const Color& color2)
|
||||
FORCE_INLINE void WriteTri(const Float2& p0, const Float2& p1, const Float2& p2, const Color& color0, const Color& color1, const Color& color2)
|
||||
{
|
||||
WriteTri(p0, p1, p2, Float2::Zero, Float2::Zero, Float2::Zero, color0, color1, color2);
|
||||
}
|
||||
|
||||
void WriteTri(const Float2& p0, const Float2& p1, const Float2& p2, const Float2& uv0, const Float2& uv1, const Float2& uv2)
|
||||
FORCE_INLINE void WriteTri(const Float2& p0, const Float2& p1, const Float2& p2, const Float2& uv0, const Float2& uv1, const Float2& uv2)
|
||||
{
|
||||
WriteTri(p0, p1, p2, uv0, uv1, uv2, Color::Black, Color::Black, Color::Black);
|
||||
}
|
||||
@@ -1816,8 +1816,8 @@ void DrawLines(const Float2* points, int32 pointsCount, const Color& color1, con
|
||||
|
||||
// Ending cap
|
||||
{
|
||||
ApplyTransform(points[0], p1t);
|
||||
ApplyTransform(points[1], p2t);
|
||||
ApplyTransform(points[pointsCount - 2], p1t);
|
||||
//ApplyTransform(points[pointsCount - 1], p2t);
|
||||
|
||||
const Float2 capDirection = thicknessHalf * Float2::Normalize(p2t - p1t);
|
||||
|
||||
@@ -1882,19 +1882,46 @@ void Render2D::DrawBezier(const Float2& p1, const Float2& p2, const Float2& p3,
|
||||
const Float2 d3 = p4 - p3;
|
||||
const float len = d1.Length() + d2.Length() + d3.Length();
|
||||
const int32 segmentCount = Math::Clamp(Math::CeilToInt(len * 0.05f), 1, 100);
|
||||
const float segmentCountInv = 1.0f / segmentCount;
|
||||
const float segmentCountInv = 1.0f / (float)segmentCount;
|
||||
|
||||
// Draw segmented curve
|
||||
Float2 p;
|
||||
AnimationUtils::Bezier(p1, p2, p3, p4, 0, p);
|
||||
Lines2.Clear();
|
||||
Lines2.Add(p);
|
||||
for (int32 i = 1; i <= segmentCount; i++)
|
||||
Lines2.Add(p1);
|
||||
for (int32 i = 1; i < segmentCount; i++)
|
||||
{
|
||||
const float t = i * segmentCountInv;
|
||||
const float t = (float)i * segmentCountInv;
|
||||
Float2 p;
|
||||
AnimationUtils::Bezier(p1, p2, p3, p4, t, p);
|
||||
Lines2.Add(p);
|
||||
}
|
||||
Lines2.Add(p4);
|
||||
DrawLines(Lines2.Get(), Lines2.Count(), color, color, thickness);
|
||||
}
|
||||
|
||||
void Render2D::DrawSpline(const Float2& p1, const Float2& p2, const Float2& p3, const Float2& p4, const Color& color, float thickness)
|
||||
{
|
||||
RENDER2D_CHECK_RENDERING_STATE;
|
||||
|
||||
// Find amount of segments to use
|
||||
const Float2 d1 = p2 - p1;
|
||||
const Float2 d2 = p3 - p2;
|
||||
const Float2 d3 = p4 - p3;
|
||||
const float len = d1.Length() + d2.Length() + d3.Length();
|
||||
const int32 segmentCount = Math::Clamp(Math::CeilToInt(len * 0.05f), 1, 100);
|
||||
const float segmentCountInv = 1.0f / (float)segmentCount;
|
||||
|
||||
// Draw segmented curve
|
||||
Lines2.Clear();
|
||||
Lines2.Add(p1);
|
||||
for (int32 i = 1; i < segmentCount; i++)
|
||||
{
|
||||
const float t = (float)i * segmentCountInv;
|
||||
Float2 p;
|
||||
p.X = Math::Lerp(p1.X, p4.X, t);
|
||||
AnimationUtils::Bezier(p1.Y, p2.Y, p3.Y, p4.Y, t, p.Y);
|
||||
Lines2.Add(p);
|
||||
}
|
||||
Lines2.Add(p4);
|
||||
DrawLines(Lines2.Get(), Lines2.Count(), color, color, thickness);
|
||||
}
|
||||
|
||||
@@ -1935,9 +1962,56 @@ void Render2D::DrawBlur(const Rectangle& rect, float blurStrength)
|
||||
WriteRect(rect, Color::White);
|
||||
}
|
||||
|
||||
void Render2D::DrawTriangles(const Span<Float2>& vertices, const Color& color, float thickness)
|
||||
{
|
||||
RENDER2D_CHECK_RENDERING_STATE;
|
||||
CHECK(vertices.Length() % 3 == 0);
|
||||
|
||||
Float2 points[2];
|
||||
for (int32 i = 0; i < vertices.Length(); i += 3)
|
||||
{
|
||||
#if 0
|
||||
// TODO: fix this
|
||||
DrawLines(&vertices.Get()[i], 3, color, color, thickness);
|
||||
#else
|
||||
points[0] = vertices.Get()[i + 0];
|
||||
points[1] = vertices.Get()[i + 1];
|
||||
DrawLines(points, 2, color, color, thickness);
|
||||
points[0] = vertices.Get()[i + 2];
|
||||
DrawLines(points, 2, color, color, thickness);
|
||||
points[1] = vertices.Get()[i + 0];
|
||||
DrawLines(points, 2, color, color, thickness);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Render2D::DrawTriangles(const Span<Float2>& vertices, const Span<Color>& colors, float thickness)
|
||||
{
|
||||
RENDER2D_CHECK_RENDERING_STATE;
|
||||
CHECK(vertices.Length() % 3 == 0);
|
||||
|
||||
Float2 points[2];
|
||||
Color cols[2];
|
||||
for (int32 i = 0; i < vertices.Length(); i += 3)
|
||||
{
|
||||
points[0] = vertices.Get()[i + 0];
|
||||
points[1] = vertices.Get()[i + 1];
|
||||
cols[0] = colors.Get()[i + 0];
|
||||
cols[1] = colors.Get()[i + 1];
|
||||
DrawLines(points, 2, cols[0], cols[1], thickness);
|
||||
points[0] = vertices.Get()[i + 2];
|
||||
cols[0] = colors.Get()[i + 2];
|
||||
DrawLines(points, 2, cols[0], cols[1], thickness);
|
||||
points[1] = vertices.Get()[i + 0];
|
||||
cols[1] = colors.Get()[i + 0];
|
||||
DrawLines(points, 2, cols[0], cols[1], thickness);
|
||||
}
|
||||
}
|
||||
|
||||
void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<Float2>& vertices, const Span<Float2>& uvs)
|
||||
{
|
||||
RENDER2D_CHECK_RENDERING_STATE;
|
||||
CHECK(vertices.Length() % 3 == 0);
|
||||
CHECK(vertices.Length() == uvs.Length());
|
||||
|
||||
Render2DDrawCall& drawCall = DrawCalls.AddOne();
|
||||
@@ -1952,14 +2026,24 @@ void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<Float2>& vertices
|
||||
|
||||
void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<Float2>& vertices, const Span<Float2>& uvs, const Color& color)
|
||||
{
|
||||
Color colors[3] = { (Color)color, (Color)color, (Color)color };
|
||||
Span<Color> spancolor(colors, 3);
|
||||
DrawTexturedTriangles(t, vertices, uvs, spancolor);
|
||||
RENDER2D_CHECK_RENDERING_STATE;
|
||||
CHECK(vertices.Length() % 3 == 0);
|
||||
CHECK(vertices.Length() == uvs.Length());
|
||||
|
||||
Render2DDrawCall& drawCall = DrawCalls.AddOne();
|
||||
drawCall.Type = DrawCallType::FillTexture;
|
||||
drawCall.StartIB = IBIndex;
|
||||
drawCall.CountIB = vertices.Length();
|
||||
drawCall.AsTexture.Ptr = t;
|
||||
|
||||
for (int32 i = 0; i < vertices.Length(); i += 3)
|
||||
WriteTri(vertices[i], vertices[i + 1], vertices[i + 2], uvs[i], uvs[i + 1], uvs[i + 2], color, color, color);
|
||||
}
|
||||
|
||||
void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<Float2>& vertices, const Span<Float2>& uvs, const Span<Color>& colors)
|
||||
{
|
||||
RENDER2D_CHECK_RENDERING_STATE;
|
||||
CHECK(vertices.Length() % 3 == 0);
|
||||
CHECK(vertices.Length() == uvs.Length());
|
||||
CHECK(vertices.Length() == colors.Length());
|
||||
|
||||
@@ -1994,6 +2078,19 @@ void Render2D::DrawTexturedTriangles(GPUTexture* t, const Span<uint16>& indices,
|
||||
}
|
||||
}
|
||||
|
||||
void Render2D::FillTriangles(const Span<Float2>& vertices, const Color& color)
|
||||
{
|
||||
RENDER2D_CHECK_RENDERING_STATE;
|
||||
|
||||
Render2DDrawCall& drawCall = DrawCalls.AddOne();
|
||||
drawCall.Type = NeedAlphaWithTint(color) ? DrawCallType::FillRect : DrawCallType::FillRectNoAlpha;
|
||||
drawCall.StartIB = IBIndex;
|
||||
drawCall.CountIB = vertices.Length();
|
||||
|
||||
for (int32 i = 0; i < vertices.Length(); i += 3)
|
||||
WriteTri(vertices[i], vertices[i + 1], vertices[i + 2], color, color, color);
|
||||
}
|
||||
|
||||
void Render2D::FillTriangles(const Span<Float2>& vertices, const Span<Color>& colors, bool useAlpha)
|
||||
{
|
||||
CHECK(vertices.Length() == colors.Length());
|
||||
|
||||
@@ -389,6 +389,17 @@ public:
|
||||
/// <param name="thickness">The line thickness.</param>
|
||||
API_FUNCTION() static void DrawBezier(const Float2& p1, const Float2& p2, const Float2& p3, const Float2& p4, const Color& color, float thickness = 1.0f);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a spline curve (Bezier but X axis represents uniform time).
|
||||
/// </summary>
|
||||
/// <param name="p1">The start point.</param>
|
||||
/// <param name="p2">The first control point.</param>
|
||||
/// <param name="p3">The second control point.</param>
|
||||
/// <param name="p4">The end point.</param>
|
||||
/// <param name="color">The line color</param>
|
||||
/// <param name="thickness">The line thickness.</param>
|
||||
API_FUNCTION() static void DrawSpline(const Float2& p1, const Float2& p2, const Float2& p3, const Float2& p4, const Color& color, float thickness = 1.0f);
|
||||
|
||||
/// <summary>
|
||||
/// Draws the GUI material.
|
||||
/// </summary>
|
||||
@@ -404,6 +415,22 @@ public:
|
||||
/// <param name="blurStrength">The blur strength defines how blurry the background is. Larger numbers increase blur, resulting in a larger runtime cost on the GPU.</param>
|
||||
API_FUNCTION() static void DrawBlur(const Rectangle& rect, float blurStrength);
|
||||
|
||||
/// <summary>
|
||||
/// Draws vertices array.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The vertices array.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <param name="thickness">The line thickness.</param>
|
||||
API_FUNCTION() static void DrawTriangles(const Span<Float2>& vertices, const Color& color, float thickness = 1.0f);
|
||||
|
||||
/// <summary>
|
||||
/// Draws vertices array.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The vertices array.</param>
|
||||
/// <param name="colors">The colors array.</param>
|
||||
/// <param name="thickness">The line thickness.</param>
|
||||
API_FUNCTION() static void DrawTriangles(const Span<Float2>& vertices, const Span<Color>& colors, float thickness = 1.0f);
|
||||
|
||||
/// <summary>
|
||||
/// Draws vertices array.
|
||||
/// </summary>
|
||||
@@ -440,13 +467,20 @@ public:
|
||||
/// <param name="colors">The colors array.</param>
|
||||
API_FUNCTION() static void DrawTexturedTriangles(GPUTexture* t, const Span<uint16>& indices, const Span<Float2>& vertices, const Span<Float2>& uvs, const Span<Color>& colors);
|
||||
|
||||
/// <summary>
|
||||
/// Draws vertices array.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The vertices array.</param>
|
||||
/// <param name="color">The color.</param>
|
||||
API_FUNCTION() static void FillTriangles(const Span<Float2>& vertices, const Color& color);
|
||||
|
||||
/// <summary>
|
||||
/// Draws vertices array.
|
||||
/// </summary>
|
||||
/// <param name="vertices">The vertices array.</param>
|
||||
/// <param name="colors">The colors array.</param>
|
||||
/// <param name="useAlpha">If true alpha blending will be enabled.</param>
|
||||
API_FUNCTION() static void FillTriangles(const Span<Float2>& vertices, const Span<Color>& colors, bool useAlpha);
|
||||
API_FUNCTION() static void FillTriangles(const Span<Float2>& vertices, const Span<Color>& colors, bool useAlpha = true);
|
||||
|
||||
/// <summary>
|
||||
/// Fills a triangular area.
|
||||
|
||||
@@ -271,7 +271,7 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input,
|
||||
|
||||
// Calculate star texture rotation matrix
|
||||
Float3 camX = renderContext.View.View.GetRight();
|
||||
Float3 camZ = renderContext.View.View.GetForward();
|
||||
Float3 camZ = renderContext.View.View.GetBackward();
|
||||
float camRot = Float3::Dot(camX, Float3::Forward) + Float3::Dot(camZ, Float3::Up);
|
||||
float camRotCos = Math::Cos(camRot) * 0.8f;
|
||||
float camRotSin = Math::Sin(camRot) * 0.8f;
|
||||
|
||||
42
Source/Engine/Scripting/Attributes/Editor/ButtonAttribute.cs
Normal file
42
Source/Engine/Scripting/Attributes/Editor/ButtonAttribute.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Displays the method in the properties panel where user can click and invoke this method.
|
||||
/// </summary>
|
||||
/// <remarks>Supported on both static and member methods that are parameterless.</remarks>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public sealed class ButtonAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The button text. Empty value will use method name (auto-formatted).
|
||||
/// </summary>
|
||||
public string Text;
|
||||
|
||||
/// <summary>
|
||||
/// The button tooltip text. Empty value will use method documentation.
|
||||
/// </summary>
|
||||
public string Tooltip;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ButtonAttribute"/> class.
|
||||
/// </summary>
|
||||
public ButtonAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ButtonAttribute"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The button text.</param>
|
||||
/// <param name="tooltip">The button tooltip.</param>
|
||||
public ButtonAttribute(string text, string tooltip = null)
|
||||
{
|
||||
Text = text;
|
||||
Tooltip = tooltip;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,11 @@
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Debug/DebugDraw.h"
|
||||
#endif
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/DynamicBuffer.h"
|
||||
#include "Engine/Engine/Units.h"
|
||||
#endif
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Assets/RawDataAsset.h"
|
||||
|
||||
@@ -94,7 +99,8 @@ void TerrainPatch::Init(Terrain* terrain, int16 x, int16 z)
|
||||
}
|
||||
#endif
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
_debugLines.Resize(0);
|
||||
SAFE_DELETE(_debugLines);
|
||||
_debugLinesDirty = true;
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
@@ -1822,7 +1828,7 @@ bool TerrainPatch::UpdateHeightData(TerrainDataUpdateInfo& info, const Int2& mod
|
||||
|
||||
// Invalidate cache
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
_debugLines.Resize(0);
|
||||
_debugLinesDirty = true;
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
@@ -1940,7 +1946,7 @@ bool TerrainPatch::UpdateCollision()
|
||||
{
|
||||
// Invalidate cache
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
_debugLines.Resize(0);
|
||||
_debugLinesDirty = true;
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
@@ -2082,7 +2088,7 @@ void TerrainPatch::UpdatePostManualDeserialization()
|
||||
{
|
||||
// Invalidate cache
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
_debugLines.Resize(0);
|
||||
_debugLinesDirty = true;
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
@@ -2211,7 +2217,8 @@ void TerrainPatch::DestroyCollision()
|
||||
_physicsShape = nullptr;
|
||||
_physicsHeightField = nullptr;
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
_debugLines.Resize(0);
|
||||
_debugLinesDirty = true;
|
||||
SAFE_DELETE(_debugLines);
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
_collisionTriangles.Resize(0);
|
||||
@@ -2224,15 +2231,26 @@ void TerrainPatch::DestroyCollision()
|
||||
void TerrainPatch::CacheDebugLines()
|
||||
{
|
||||
PROFILE_CPU();
|
||||
ASSERT(_debugLines.IsEmpty() && _physicsHeightField);
|
||||
ASSERT(_physicsHeightField);
|
||||
_debugLinesDirty = false;
|
||||
if (!_debugLines)
|
||||
_debugLines = GPUDevice::Instance->CreateBuffer(TEXT("Terrain.DebugLines"));
|
||||
|
||||
int32 rows, cols;
|
||||
PhysicsBackend::GetHeightFieldSize(_physicsHeightField, rows, cols);
|
||||
const int32 count = (rows - 1) * (cols - 1) * 6 + (cols + rows - 2) * 2;
|
||||
typedef DebugDraw::Vertex Vertex;
|
||||
if (_debugLines->GetElementsCount() != count)
|
||||
{
|
||||
if (_debugLines->Init(GPUBufferDescription::Vertex(sizeof(Vertex), count)))
|
||||
return;
|
||||
}
|
||||
Array<Vertex> debugLines;
|
||||
debugLines.Resize(count);
|
||||
auto* data = debugLines.Get();
|
||||
const Color32 color(Color::GreenYellow * 0.8f);
|
||||
|
||||
_debugLines.Resize((rows - 1) * (cols - 1) * 6 + (cols + rows - 2) * 2);
|
||||
Vector3* data = _debugLines.Get();
|
||||
|
||||
#define GET_VERTEX(x, y) const Vector3 v##x##y((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, row + (x), col + (y)) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y)))
|
||||
#define GET_VERTEX(x, y) const Vertex v##x##y = { Float3((float)(row + (x)), PhysicsBackend::GetHeightFieldHeight(_physicsHeightField, row + (x), col + (y)) / TERRAIN_PATCH_COLLISION_QUANTIZATION, (float)(col + (y))), color }
|
||||
|
||||
for (int32 row = 0; row < rows - 1; row++)
|
||||
{
|
||||
@@ -2243,7 +2261,7 @@ void TerrainPatch::CacheDebugLines()
|
||||
if (sample.MaterialIndex0 == (uint8)PhysicsBackend::HeightFieldMaterial::Hole)
|
||||
{
|
||||
for (int32 i = 0; i < 6; i++)
|
||||
*data++ = Vector3::Zero;
|
||||
*data++ = Vertex { Float3::Zero, Color32::Black };
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2284,18 +2302,16 @@ void TerrainPatch::CacheDebugLines()
|
||||
}
|
||||
|
||||
#undef GET_VERTEX
|
||||
|
||||
_debugLines->SetData(debugLines.Get(), _debugLines->GetSize());
|
||||
}
|
||||
|
||||
void TerrainPatch::DrawPhysicsDebug(RenderView& view)
|
||||
{
|
||||
#if COMPILE_WITH_DEBUG_DRAW
|
||||
const BoundingBox bounds(_bounds.Minimum - view.Origin, _bounds.Maximum - view.Origin);
|
||||
if (!_physicsShape || !view.CullingFrustum.Intersects(bounds))
|
||||
return;
|
||||
|
||||
const Transform terrainTransform = _terrain->_transform;
|
||||
const Transform localTransform(Vector3(0, _yOffset, 0), Quaternion::Identity, Vector3(_collisionScaleXZ, _yHeight, _collisionScaleXZ));
|
||||
const Matrix world = localTransform.GetWorld() * terrainTransform.GetWorld();
|
||||
|
||||
if (view.Mode == ViewMode::PhysicsColliders)
|
||||
{
|
||||
DEBUG_DRAW_TRIANGLES(GetCollisionTriangles(), Color::DarkOliveGreen, 0, true);
|
||||
@@ -2304,13 +2320,17 @@ void TerrainPatch::DrawPhysicsDebug(RenderView& view)
|
||||
{
|
||||
BoundingSphere sphere;
|
||||
BoundingSphere::FromBox(bounds, sphere);
|
||||
if (Vector3::Distance(sphere.Center, view.Position) - sphere.Radius < 4000.0f)
|
||||
if (Vector3::Distance(sphere.Center, view.Position) - sphere.Radius < METERS_TO_UNITS(500))
|
||||
{
|
||||
if (_debugLines.IsEmpty())
|
||||
if (!_debugLines || _debugLinesDirty)
|
||||
CacheDebugLines();
|
||||
DEBUG_DRAW_LINES(_debugLines, world, Color::GreenYellow * 0.8f, 0, true);
|
||||
const Transform terrainTransform = _terrain->_transform;
|
||||
const Transform localTransform(Vector3(0, _yOffset, 0), Quaternion::Identity, Vector3(_collisionScaleXZ, _yHeight, _collisionScaleXZ));
|
||||
const Matrix world = localTransform.GetWorld() * terrainTransform.GetWorld();
|
||||
DebugDraw::DrawLines(_debugLines, world);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -40,12 +40,13 @@ private:
|
||||
Array<Color32> _cachedSplatMap[TERRAIN_MAX_SPLATMAPS_COUNT];
|
||||
bool _wasHeightModified;
|
||||
bool _wasSplatmapModified[TERRAIN_MAX_SPLATMAPS_COUNT];
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
bool _debugLinesDirty = true;
|
||||
class GPUBuffer* _debugLines = nullptr;
|
||||
#endif
|
||||
TextureBase::InitData* _dataHeightmap = nullptr;
|
||||
TextureBase::InitData* _dataSplatmap[TERRAIN_MAX_SPLATMAPS_COUNT] = {};
|
||||
#endif
|
||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||
Array<Vector3> _debugLines; // TODO: large-worlds
|
||||
#endif
|
||||
#if USE_EDITOR
|
||||
Array<Vector3> _collisionTriangles; // TODO: large-worlds
|
||||
#endif
|
||||
|
||||
@@ -263,16 +263,21 @@ namespace FlaxEngine.GUI
|
||||
/// <inheritdoc />
|
||||
protected override void SetViewOffset(ref Float2 value)
|
||||
{
|
||||
// Update scroll bars but with locked layout
|
||||
bool wasLocked = _isLayoutLocked;
|
||||
int layoutUpdateLock = _layoutUpdateLock;
|
||||
_isLayoutLocked = true;
|
||||
|
||||
_layoutUpdateLock = 999;
|
||||
if (HScrollBar != null)
|
||||
HScrollBar.Value = -value.X;
|
||||
HScrollBar.TargetValue = -value.X;
|
||||
if (VScrollBar != null)
|
||||
VScrollBar.Value = -value.Y;
|
||||
|
||||
VScrollBar.TargetValue = -value.Y;
|
||||
_layoutUpdateLock = layoutUpdateLock;
|
||||
_isLayoutLocked = wasLocked;
|
||||
|
||||
base.SetViewOffset(ref value);
|
||||
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -553,7 +558,12 @@ namespace FlaxEngine.GUI
|
||||
|
||||
if (vScrollEnabled)
|
||||
{
|
||||
VScrollBar.SetScrollRange(scrollBounds.Top, Mathf.Max(Mathf.Max(0, scrollBounds.Top), scrollBounds.Height - height));
|
||||
float max;
|
||||
if (scrollBounds.Top < 0)
|
||||
max = Mathf.Max(scrollBounds.Bottom, scrollBounds.Top + scrollBounds.Height - height);
|
||||
else
|
||||
max = Mathf.Max(scrollBounds.Top, scrollBounds.Height - height);
|
||||
VScrollBar.SetScrollRange(scrollBounds.Top, max);
|
||||
}
|
||||
VScrollBar.Bounds = new Rectangle(Width - _scrollBarsSize, 0, _scrollBarsSize, Height);
|
||||
}
|
||||
@@ -580,7 +590,12 @@ namespace FlaxEngine.GUI
|
||||
|
||||
if (hScrollEnabled)
|
||||
{
|
||||
HScrollBar.SetScrollRange(scrollBounds.Left, Mathf.Max(Mathf.Max(0, scrollBounds.Left), scrollBounds.Width - width));
|
||||
float max;
|
||||
if (scrollBounds.Left < 0)
|
||||
max = Mathf.Max(scrollBounds.Right, scrollBounds.Left + scrollBounds.Width - width);
|
||||
else
|
||||
max = Mathf.Max(scrollBounds.Left, scrollBounds.Width - width);
|
||||
HScrollBar.SetScrollRange(scrollBounds.Left, max);
|
||||
}
|
||||
HScrollBar.Bounds = new Rectangle(0, Height - _scrollBarsSize, Width - (VScrollBar != null && VScrollBar.Visible ? VScrollBar.Width : 0), _scrollBarsSize);
|
||||
}
|
||||
@@ -596,17 +611,29 @@ namespace FlaxEngine.GUI
|
||||
// Calculate scroll area bounds
|
||||
var totalMin = Float2.Zero;
|
||||
var totalMax = Float2.Zero;
|
||||
var hasTotal = false;
|
||||
for (int i = 0; i < _children.Count; i++)
|
||||
{
|
||||
var c = _children[i];
|
||||
if (c.Visible && c.IsScrollable)
|
||||
{
|
||||
var min = Float2.Zero;
|
||||
var max = c.Size;
|
||||
Matrix3x3.Transform2D(ref min, ref c._cachedTransform, out min);
|
||||
Matrix3x3.Transform2D(ref max, ref c._cachedTransform, out max);
|
||||
Float2.Min(ref min, ref totalMin, out totalMin);
|
||||
Float2.Max(ref max, ref totalMax, out totalMax);
|
||||
var upperLeft = Float2.Zero;
|
||||
var bottomRight = c.Size;
|
||||
Matrix3x3.Transform2D(ref upperLeft, ref c._cachedTransform, out upperLeft);
|
||||
Matrix3x3.Transform2D(ref bottomRight, ref c._cachedTransform, out bottomRight);
|
||||
Float2.Min(ref upperLeft, ref bottomRight, out var min);
|
||||
Float2.Max(ref upperLeft, ref bottomRight, out var max);
|
||||
if (hasTotal)
|
||||
{
|
||||
Float2.Min(ref min, ref totalMin, out totalMin);
|
||||
Float2.Max(ref max, ref totalMax, out totalMax);
|
||||
}
|
||||
else
|
||||
{
|
||||
totalMin = min;
|
||||
totalMax = max;
|
||||
hasTotal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -348,6 +348,8 @@ namespace FlaxEngine.GUI
|
||||
|
||||
// https://easings.net/#easeOutSine
|
||||
var easedProgress = Mathf.Sin((progress * Mathf.Pi) / 2);
|
||||
if (progress >= 1.0f)
|
||||
easedProgress = 1.0f;
|
||||
value = Mathf.Lerp(_startValue, _targetValue, easedProgress);
|
||||
|
||||
_scrollAnimationProgress = progress;
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
|
||||
/// <summary>
|
||||
/// Helper class with Delaunay triangulation algorithm implementation,
|
||||
/// Helper class with Delaunay triangulation algorithm implementation (2D space).
|
||||
/// </summary>
|
||||
class Delaunay2D
|
||||
API_CLASS(Internal, Static, Namespace="FlaxEngine.Utilities") class Delaunay2D
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(Delaunay2D);
|
||||
public:
|
||||
struct Triangle
|
||||
{
|
||||
@@ -31,14 +32,35 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename TVertexArray, typename TTrianglesArray>
|
||||
static void Triangulate(const TVertexArray& vertices, TTrianglesArray& triangles)
|
||||
/// <summary>
|
||||
/// Triangulates input vertices array into the list of triangle vertices.
|
||||
/// </summary>
|
||||
/// <param name="vertices">Input list of vertices.</param>
|
||||
/// <returns>Result list of triangles. Each triangle is made out of sequence of 3 vertices. Empty if no valid triangle built.</returns>
|
||||
API_FUNCTION() static Array<Float2> Triangulate(const Array<Float2>& vertices)
|
||||
{
|
||||
Array<Triangle> triangles;
|
||||
Triangulate(vertices, triangles);
|
||||
Array<Float2> result;
|
||||
result.Resize(triangles.Count() * 3);
|
||||
int32 c = 0;
|
||||
for (const Triangle& t : triangles)
|
||||
{
|
||||
result.Get()[c++] = vertices[t.Indices[0]];
|
||||
result.Get()[c++] = vertices[t.Indices[1]];
|
||||
result.Get()[c++] = vertices[t.Indices[2]];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename TrianglesArray = Triangle>
|
||||
static void Triangulate(const Array<Float2>& vertices, TrianglesArray& triangles)
|
||||
{
|
||||
// Skip if no change to produce any triangles
|
||||
if (vertices.Count() < 3)
|
||||
if (vertices.Count() < 3)
|
||||
return;
|
||||
|
||||
TVertexArray points = vertices;
|
||||
Array<Float2> points = vertices;
|
||||
Array<Edge> polygon;
|
||||
|
||||
Rectangle rect;
|
||||
@@ -142,8 +164,7 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename TVertexArray>
|
||||
static bool CircumCircleContains(const TVertexArray& vertices, const Triangle& triangle, int vertexIndex)
|
||||
static bool CircumCircleContains(const Array<Float2>& vertices, const Triangle& triangle, int32 vertexIndex)
|
||||
{
|
||||
Float2 p1 = vertices[triangle.Indices[0]];
|
||||
Float2 p2 = vertices[triangle.Indices[1]];
|
||||
@@ -157,25 +178,20 @@ private:
|
||||
(ab * (p3.Y - p2.Y) + cd * (p1.Y - p3.Y) + ef * (p2.Y - p1.Y)) / (p1.X * (p3.Y - p2.Y) + p2.X * (p1.Y - p3.Y) + p3.X * (p2.Y - p1.Y)),
|
||||
(ab * (p3.X - p2.X) + cd * (p1.X - p3.X) + ef * (p2.X - p1.X)) / (p1.Y * (p3.X - p2.X) + p2.Y * (p1.X - p3.X) + p3.Y * (p2.X - p1.X)));
|
||||
|
||||
circum *= 0.5;
|
||||
circum *= 0.5f;
|
||||
float r = Float2::DistanceSquared(p1, circum);
|
||||
float d = Float2::DistanceSquared(vertices[vertexIndex], circum);
|
||||
return d <= r;
|
||||
}
|
||||
|
||||
template<typename TVertexArray>
|
||||
static bool EdgeCompare(const TVertexArray& vertices, const Edge& a, const Edge& b)
|
||||
static bool EdgeCompare(const Array<Float2>& vertices, const Edge& a, const Edge& b)
|
||||
{
|
||||
if (Float2::Distance(vertices[a.Indices[0]], vertices[b.Indices[0]]) < ZeroTolerance && Vector2::Distance(vertices[a.Indices[1]], vertices[b.Indices[1]]) < ZeroTolerance)
|
||||
{
|
||||
if (Float2::Distance(vertices[a.Indices[0]], vertices[b.Indices[0]]) < ZeroTolerance &&
|
||||
Float2::Distance(vertices[a.Indices[1]], vertices[b.Indices[1]]) < ZeroTolerance)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Float2::Distance(vertices[a.Indices[0]], vertices[b.Indices[1]]) < ZeroTolerance && Vector2::Distance(vertices[a.Indices[1]], vertices[b.Indices[0]]) < ZeroTolerance)
|
||||
{
|
||||
if (Float2::Distance(vertices[a.Indices[0]], vertices[b.Indices[1]]) < ZeroTolerance &&
|
||||
Float2::Distance(vertices[a.Indices[1]], vertices[b.Indices[0]]) < ZeroTolerance)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -92,9 +92,13 @@ void ShaderGenerator::ProcessGroupConstants(Box* box, Node* node, Value& value)
|
||||
value = Value(cv.W);
|
||||
break;
|
||||
}
|
||||
// Rotation
|
||||
case 8:
|
||||
{
|
||||
value = Value::Zero;
|
||||
const float pitch = (float)node->Values[0];
|
||||
const float yaw = (float)node->Values[1];
|
||||
const float roll = (float)node->Values[2];
|
||||
value = Value(Quaternion::Euler(pitch, yaw, roll));
|
||||
break;
|
||||
}
|
||||
// PI
|
||||
|
||||
@@ -460,6 +460,7 @@ ShaderGraphValue ShaderGraphValue::Cast(const ShaderGraphValue& v, VariantType::
|
||||
case VariantType::Types::Float4:
|
||||
case VariantType::Types::Double4:
|
||||
case VariantType::Types::Color:
|
||||
case VariantType::Types::Quaternion:
|
||||
switch (v.Type)
|
||||
{
|
||||
case VariantType::Types::Bool:
|
||||
@@ -485,16 +486,6 @@ ShaderGraphValue ShaderGraphValue::Cast(const ShaderGraphValue& v, VariantType::
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VariantType::Types::Quaternion:
|
||||
switch (v.Type)
|
||||
{
|
||||
case VariantType::Types::Color:
|
||||
case VariantType::Types::Float4:
|
||||
case VariantType::Types::Double4:
|
||||
format = TEXT("{}");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (format == nullptr)
|
||||
{
|
||||
|
||||
@@ -79,6 +79,7 @@ void VisjectExecutor::ProcessGroupConstants(Box* box, Node* node, Value& value)
|
||||
value = cv.W;
|
||||
break;
|
||||
}
|
||||
// Rotation
|
||||
case 8:
|
||||
{
|
||||
const float pitch = (float)node->Values[0];
|
||||
|
||||
Reference in New Issue
Block a user