Add support for curves in C++ scripting api

#2546
This commit is contained in:
Wojtek Figat
2024-12-04 13:30:56 +01:00
parent c01824cd09
commit 12d9d94138
5 changed files with 131 additions and 23 deletions

View File

@@ -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
@@ -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>
@@ -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));
}
}
}

View File

@@ -501,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;
@@ -763,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>>;

View File

@@ -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();
}