@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>>;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace Flax.Build.Bindings
|
||||
private static readonly Dictionary<string, string> CSharpAdditionalCodeCache = new Dictionary<string, string>();
|
||||
#if USE_NETCORE
|
||||
private static readonly TypeInfo CSharpEventBindReturn = new TypeInfo("void");
|
||||
private static readonly List<FunctionInfo.ParameterInfo> CSharpEventBindParams = new List<FunctionInfo.ParameterInfo>() { new FunctionInfo.ParameterInfo() { Name = "bind", Type = new TypeInfo("bool") } };
|
||||
private static readonly List<FunctionInfo.ParameterInfo> CSharpEventBindParams = new List<FunctionInfo.ParameterInfo> { new FunctionInfo.ParameterInfo { Name = "bind", Type = new TypeInfo("bool") } };
|
||||
#endif
|
||||
|
||||
public static event Action<BuildData, ApiTypeInfo, StringBuilder, string> GenerateCSharpTypeInternals;
|
||||
|
||||
internal static readonly Dictionary<string, string> CSharpNativeToManagedBasicTypes = new Dictionary<string, string>()
|
||||
internal static readonly Dictionary<string, string> CSharpNativeToManagedBasicTypes = new Dictionary<string, string>
|
||||
{
|
||||
// Language types
|
||||
{ "bool", "bool" },
|
||||
@@ -46,7 +46,7 @@ namespace Flax.Build.Bindings
|
||||
{ "double", "double" },
|
||||
};
|
||||
|
||||
internal static readonly Dictionary<string, string> CSharpNativeToManagedDefault = new Dictionary<string, string>()
|
||||
internal static readonly Dictionary<string, string> CSharpNativeToManagedDefault = new Dictionary<string, string>
|
||||
{
|
||||
// Engine types
|
||||
{ "String", "string" },
|
||||
@@ -632,11 +632,11 @@ namespace Flax.Build.Bindings
|
||||
else if (returnValueType == "object[]")
|
||||
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))";
|
||||
else if (functionInfo.ReturnType.Type == "Array" || functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "DataContainer" || functionInfo.ReturnType.Type == "BytesContainer" || returnNativeType == "Array")
|
||||
returnMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = nameof(__returnCount))";
|
||||
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = nameof(__returnCount))";
|
||||
else if (functionInfo.ReturnType.Type == "Dictionary")
|
||||
returnMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
|
||||
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
|
||||
else if (returnValueType == "byte[]")
|
||||
returnMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__returnCount\")";
|
||||
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__returnCount\")";
|
||||
else if (returnValueType == "bool[]")
|
||||
{
|
||||
// Boolean arrays does not support custom marshalling for some unknown reason
|
||||
@@ -691,11 +691,15 @@ namespace Flax.Build.Bindings
|
||||
parameterMarshalType += ", In"; // The usage of 'LibraryImportAttribute' does not follow recommendations. It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters.
|
||||
}
|
||||
else if (parameterInfo.Type.Type == "Dictionary")
|
||||
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
|
||||
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
|
||||
else if (nativeType == "bool")
|
||||
parameterMarshalType = "MarshalAs(UnmanagedType.U1)";
|
||||
else if (nativeType == "char")
|
||||
parameterMarshalType = "MarshalAs(UnmanagedType.I2)";
|
||||
else if (nativeType.EndsWith("[]"))
|
||||
{
|
||||
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>))";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(parameterMarshalType))
|
||||
contents.Append($"[{parameterMarshalType}] ");
|
||||
@@ -730,7 +734,7 @@ namespace Flax.Build.Bindings
|
||||
if (parameterInfo.Type.Type == "Array" || parameterInfo.Type.Type == "Span" || parameterInfo.Type.Type == "DataContainer" || parameterInfo.Type.Type == "BytesContainer")
|
||||
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"{parameterInfo.Name}Count\")";
|
||||
else if (parameterInfo.Type.Type == "Dictionary")
|
||||
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
|
||||
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
|
||||
}
|
||||
if (nativeType == "System.Type")
|
||||
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemTypeMarshaller))";
|
||||
|
||||
@@ -980,6 +980,10 @@ namespace Flax.Build.Bindings
|
||||
UseReferenceForResult = UsePassByReference(buildData, functionInfo.ReturnType, caller),
|
||||
CustomParameters = new List<FunctionInfo.ParameterInfo>(),
|
||||
};
|
||||
var returnType = functionInfo.ReturnType;
|
||||
var returnApiType = FindApiTypeInfo(buildData, returnType, caller);
|
||||
if (returnApiType != null && returnApiType.MarshalAs != null)
|
||||
returnType = returnApiType.MarshalAs;
|
||||
|
||||
bool returnTypeIsContainer = false;
|
||||
var returnValueConvert = GenerateCppWrapperNativeToManaged(buildData, functionInfo.ReturnType, caller, out var returnValueType, functionInfo);
|
||||
@@ -999,7 +1003,7 @@ namespace Flax.Build.Bindings
|
||||
});
|
||||
}
|
||||
#if USE_NETCORE
|
||||
else if (functionInfo.ReturnType.Type == "Array" || functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "DataContainer" || functionInfo.ReturnType.Type == "BitArray" || functionInfo.ReturnType.Type == "BytesContainer")
|
||||
else if (returnType.Type == "Array" || returnType.Type == "Span" || returnType.Type == "DataContainer" || returnType.Type == "BitArray" || returnType.Type == "BytesContainer")
|
||||
{
|
||||
returnTypeIsContainer = true;
|
||||
functionInfo.Glue.CustomParameters.Add(new FunctionInfo.ParameterInfo
|
||||
@@ -1173,7 +1177,7 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
callBegin += "*__resultAsRef = ";
|
||||
}
|
||||
else if (!functionInfo.ReturnType.IsVoid)
|
||||
else if (!returnType.IsVoid)
|
||||
{
|
||||
if (useInlinedReturn)
|
||||
callBegin += "return ";
|
||||
@@ -1186,7 +1190,7 @@ namespace Flax.Build.Bindings
|
||||
if (returnTypeIsContainer)
|
||||
{
|
||||
callReturnCount = indent;
|
||||
if (functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "BytesContainer")
|
||||
if (returnType.Type == "Span" || returnType.Type == "BytesContainer")
|
||||
callReturnCount += "*__returnCount = {0}.Length();";
|
||||
else
|
||||
callReturnCount += "*__returnCount = {0}.Count();";
|
||||
@@ -1278,7 +1282,8 @@ namespace Flax.Build.Bindings
|
||||
#if USE_NETCORE
|
||||
if (!string.IsNullOrEmpty(callReturnCount))
|
||||
{
|
||||
contents.Append(indent).Append("const auto& __callTemp = ").Append(string.Format(callFormat, call, callParams)).Append(";").AppendLine();
|
||||
var tempVar = returnTypeIsContainer && returnType != functionInfo.ReturnType ? $"{returnType} __callTemp = " : "const auto& __callTemp = ";
|
||||
contents.Append(indent).Append(tempVar).Append(string.Format(callFormat, call, callParams)).Append(";").AppendLine();
|
||||
call = "__callTemp";
|
||||
contents.Append(string.Format(callReturnCount, call));
|
||||
contents.AppendLine();
|
||||
@@ -1357,7 +1362,7 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
}
|
||||
|
||||
if (!useInlinedReturn && !functionInfo.Glue.UseReferenceForResult && !functionInfo.ReturnType.IsVoid)
|
||||
if (!useInlinedReturn && !functionInfo.Glue.UseReferenceForResult && !returnType.IsVoid)
|
||||
{
|
||||
contents.Append(indent).Append("return __result;").AppendLine();
|
||||
}
|
||||
@@ -1817,6 +1822,10 @@ namespace Flax.Build.Bindings
|
||||
// Add includes to properly compile bindings (eg. SoftObjectReference<class Texture>)
|
||||
GenerateCppAddFileReference(buildData, caller, typeInfo, apiTypeInfo);
|
||||
|
||||
// TODO: find a better way to reference other include files for types that have separate serialization header
|
||||
if (typeInfo.Type.EndsWith("Curve") && typeInfo.GenericArgs != null)
|
||||
CppIncludeFilesList.Add("Engine/Animations/CurveSerialization.h");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3126,13 +3135,12 @@ namespace Flax.Build.Bindings
|
||||
// Includes
|
||||
header.Clear();
|
||||
CppReferencesFiles.Remove(null);
|
||||
CppIncludeFilesList.Clear();
|
||||
foreach (var fileInfo in CppReferencesFiles)
|
||||
CppIncludeFilesList.Add(fileInfo.Name);
|
||||
CppIncludeFilesList.AddRange(CppIncludeFiles);
|
||||
CppIncludeFilesList.Sort();
|
||||
if (CppIncludeFilesList.Remove("Engine/Serialization/Serialization.h"))
|
||||
CppIncludeFilesList.Add("Engine/Serialization/Serialization.h");
|
||||
CppIncludeFilesList.Add("Engine/Serialization/Serialization.h"); // Include serialization header as the last one to properly handle specialization of custom types serialization
|
||||
foreach (var path in CppIncludeFilesList)
|
||||
header.AppendFormat("#include \"{0}\"", path).AppendLine();
|
||||
contents.Insert(headerPos, header.ToString());
|
||||
|
||||
Reference in New Issue
Block a user