Merge remote-tracking branch 'origin/1.5' into dotnet7
This commit is contained in:
@@ -144,11 +144,11 @@ public:
|
|||||||
/// <returns>The reference to this.</returns>
|
/// <returns>The reference to this.</returns>
|
||||||
Array& operator=(std::initializer_list<T> initList) noexcept
|
Array& operator=(std::initializer_list<T> initList) noexcept
|
||||||
{
|
{
|
||||||
Memory::DestructItems(_allocation.Get(), _count);
|
Clear();
|
||||||
_count = _capacity = (int32)initList.size();
|
if (initList.size() > 0)
|
||||||
if (_capacity > 0)
|
|
||||||
{
|
{
|
||||||
_allocation.Allocate(_capacity);
|
EnsureCapacity((int32)initList.size());
|
||||||
|
_count = (int32)initList.size();
|
||||||
Memory::ConstructItems(_allocation.Get(), initList.begin(), _count);
|
Memory::ConstructItems(_allocation.Get(), initList.begin(), _count);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
|||||||
@@ -43,6 +43,15 @@ public:
|
|||||||
{
|
{
|
||||||
return GetEnabled();
|
return GetEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this effect can be rendered.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderContext">The target render context.</param>
|
||||||
|
API_FUNCTION() virtual bool CanRender(const RenderContext& renderContext) const
|
||||||
|
{
|
||||||
|
return CanRender();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pre-rendering event called before scene rendering begin. Can be used to perform custom rendering or customize render view/setup.
|
/// Pre-rendering event called before scene rendering begin. Can be used to perform custom rendering or customize render view/setup.
|
||||||
|
|||||||
@@ -238,13 +238,13 @@ void SceneRenderTask::OnCollectDrawCalls(RenderContextBatch& renderContextBatch,
|
|||||||
{
|
{
|
||||||
for (PostProcessEffect* fx : GlobalCustomPostFx)
|
for (PostProcessEffect* fx : GlobalCustomPostFx)
|
||||||
{
|
{
|
||||||
if (fx && fx->CanRender())
|
if (fx && fx->CanRender(renderContext))
|
||||||
postFx.Add(fx);
|
postFx.Add(fx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (PostProcessEffect* fx : CustomPostFx)
|
for (PostProcessEffect* fx : CustomPostFx)
|
||||||
{
|
{
|
||||||
if (fx && fx->CanRender())
|
if (fx && fx->CanRender(renderContext))
|
||||||
postFx.Add(fx);
|
postFx.Add(fx);
|
||||||
}
|
}
|
||||||
if (const auto* camera = Camera.Get())
|
if (const auto* camera = Camera.Get())
|
||||||
@@ -252,7 +252,7 @@ void SceneRenderTask::OnCollectDrawCalls(RenderContextBatch& renderContextBatch,
|
|||||||
for (Script* script : camera->Scripts)
|
for (Script* script : camera->Scripts)
|
||||||
{
|
{
|
||||||
auto* fx = Cast<PostProcessEffect>(script);
|
auto* fx = Cast<PostProcessEffect>(script);
|
||||||
if (fx && fx->CanRender())
|
if (fx && fx->CanRender(renderContext))
|
||||||
postFx.Add(fx);
|
postFx.Add(fx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,6 +107,9 @@ void PluginManagerService::InvokeInitialize(Plugin* plugin)
|
|||||||
{
|
{
|
||||||
if (plugin->_initialized)
|
if (plugin->_initialized)
|
||||||
return;
|
return;
|
||||||
|
StringAnsiView typeName = plugin->GetType().GetName();
|
||||||
|
PROFILE_CPU();
|
||||||
|
ZoneName(typeName.Get(), typeName.Length());
|
||||||
|
|
||||||
LOG(Info, "Loading plugin {}", plugin->ToString());
|
LOG(Info, "Loading plugin {}", plugin->ToString());
|
||||||
|
|
||||||
@@ -122,6 +125,9 @@ void PluginManagerService::InvokeDeinitialize(Plugin* plugin)
|
|||||||
{
|
{
|
||||||
if (!plugin->_initialized)
|
if (!plugin->_initialized)
|
||||||
return;
|
return;
|
||||||
|
StringAnsiView typeName = plugin->GetType().GetName();
|
||||||
|
PROFILE_CPU();
|
||||||
|
ZoneName(typeName.Get(), typeName.Length())
|
||||||
|
|
||||||
LOG(Info, "Unloading plugin {}", plugin->ToString());
|
LOG(Info, "Unloading plugin {}", plugin->ToString());
|
||||||
|
|
||||||
|
|||||||
@@ -742,6 +742,23 @@ ScriptingTypeHandle Scripting::FindScriptingType(const StringAnsiView& fullname)
|
|||||||
return ScriptingTypeHandle();
|
return ScriptingTypeHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScriptingObject* Scripting::NewObject(const ScriptingTypeHandle& type)
|
||||||
|
{
|
||||||
|
if (!type)
|
||||||
|
{
|
||||||
|
LOG(Error, "Invalid type.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const ScriptingType& scriptingType = type.GetType();
|
||||||
|
|
||||||
|
// Create unmanaged object
|
||||||
|
const ScriptingObjectSpawnParams params(Guid::New(), type);
|
||||||
|
ScriptingObject* obj = scriptingType.Script.Spawn(params);
|
||||||
|
if (obj == nullptr)
|
||||||
|
LOG(Error, "Failed to spawn object of type \'{0}\'.", scriptingType.ToString());
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
ScriptingObject* Scripting::NewObject(const MClass* type)
|
ScriptingObject* Scripting::NewObject(const MClass* type)
|
||||||
{
|
{
|
||||||
if (type == nullptr)
|
if (type == nullptr)
|
||||||
@@ -772,10 +789,7 @@ ScriptingObject* Scripting::NewObject(const MClass* type)
|
|||||||
const ScriptingObjectSpawnParams params(Guid::New(), ScriptingTypeHandle(module, typeIndex));
|
const ScriptingObjectSpawnParams params(Guid::New(), ScriptingTypeHandle(module, typeIndex));
|
||||||
ScriptingObject* obj = scriptingType.Script.Spawn(params);
|
ScriptingObject* obj = scriptingType.Script.Spawn(params);
|
||||||
if (obj == nullptr)
|
if (obj == nullptr)
|
||||||
{
|
LOG(Error, "Failed to spawn object of type \'{0}\'.", scriptingType.ToString());
|
||||||
LOG(Error, "Failed to spawn object of type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return obj;
|
return obj;
|
||||||
#else
|
#else
|
||||||
LOG(Error, "Not supported object creation from Managed class.");
|
LOG(Error, "Not supported object creation from Managed class.");
|
||||||
|
|||||||
@@ -109,6 +109,13 @@ public:
|
|||||||
/// <returns>The scripting type or invalid type if missing.</returns>
|
/// <returns>The scripting type or invalid type if missing.</returns>
|
||||||
static ScriptingTypeHandle FindScriptingType(const StringAnsiView& fullname);
|
static ScriptingTypeHandle FindScriptingType(const StringAnsiView& fullname);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the given type object (native construction).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The scripting object type class.</param>
|
||||||
|
/// <returns>The created object or null if failed.</returns>
|
||||||
|
static ScriptingObject* NewObject(const ScriptingTypeHandle& type);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the given class object (native construction).
|
/// Creates a new instance of the given class object (native construction).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -16,20 +16,25 @@ TEST_CASE("Scripting")
|
|||||||
// Test native class
|
// Test native class
|
||||||
ScriptingTypeHandle type = Scripting::FindScriptingType("FlaxEngine.TestClassNative");
|
ScriptingTypeHandle type = Scripting::FindScriptingType("FlaxEngine.TestClassNative");
|
||||||
CHECK(type == TestClassNative::TypeInitializer);
|
CHECK(type == TestClassNative::TypeInitializer);
|
||||||
ScriptingObject* object = Scripting::NewObject(type.GetType().ManagedClass);
|
ScriptingObject* object = Scripting::NewObject(type);
|
||||||
CHECK(object);
|
CHECK(object);
|
||||||
CHECK(object->Is<TestClassNative>());
|
CHECK(object->Is<TestClassNative>());
|
||||||
TestClassNative* testClass = (TestClassNative*)object;
|
TestClassNative* testClass = (TestClassNative*)object;
|
||||||
CHECK(testClass->SimpleField == 1);
|
CHECK(testClass->SimpleField == 1);
|
||||||
CHECK(testClass->SimpleStruct.Object == nullptr);
|
CHECK(testClass->SimpleStruct.Object == nullptr);
|
||||||
CHECK(testClass->SimpleStruct.Vector == Float3::One);
|
CHECK(testClass->SimpleStruct.Vector == Float3::One);
|
||||||
int32 methodResult = testClass->TestMethod(TEXT("123"));
|
Array<TestStruct> struct1 = { testClass->SimpleStruct };
|
||||||
|
Array<TestStruct> struct2 = { testClass->SimpleStruct };
|
||||||
|
Array<ScriptingObject*> objects;
|
||||||
|
TestStructPOD pod;
|
||||||
|
int32 methodResult = testClass->TestMethod(TEXT("123"), pod, struct1, struct2, objects);
|
||||||
CHECK(methodResult == 3);
|
CHECK(methodResult == 3);
|
||||||
|
CHECK(objects.Count() == 0);
|
||||||
|
|
||||||
// Test managed class
|
// Test managed class
|
||||||
type = Scripting::FindScriptingType("FlaxEngine.TestClassManaged");
|
type = Scripting::FindScriptingType("FlaxEngine.TestClassManaged");
|
||||||
CHECK(type);
|
CHECK(type);
|
||||||
object = Scripting::NewObject(type.GetType().ManagedClass);
|
object = Scripting::NewObject(type);
|
||||||
CHECK(object);
|
CHECK(object);
|
||||||
CHECK(object->Is<TestClassNative>());
|
CHECK(object->Is<TestClassNative>());
|
||||||
testClass = (TestClassNative*)object;
|
testClass = (TestClassNative*)object;
|
||||||
@@ -38,15 +43,24 @@ TEST_CASE("Scripting")
|
|||||||
CHECK(testClass->SimpleField == 2);
|
CHECK(testClass->SimpleField == 2);
|
||||||
CHECK(testClass->SimpleStruct.Object == testClass);
|
CHECK(testClass->SimpleStruct.Object == testClass);
|
||||||
CHECK(testClass->SimpleStruct.Vector == Float3::UnitX);
|
CHECK(testClass->SimpleStruct.Vector == Float3::UnitX);
|
||||||
methodResult = testClass->TestMethod(TEXT("123"));
|
struct1 = { testClass->SimpleStruct };
|
||||||
|
struct2 = { testClass->SimpleStruct };
|
||||||
|
objects.Clear();
|
||||||
|
pod.Vector = Float3::One;
|
||||||
|
methodResult = testClass->TestMethod(TEXT("123"), pod, struct1, struct2, objects);
|
||||||
CHECK(methodResult == 6);
|
CHECK(methodResult == 6);
|
||||||
|
CHECK(pod.Vector == Float3::Half);
|
||||||
|
CHECK(struct2.Count() == 2);
|
||||||
|
CHECK(struct2[0] == testClass->SimpleStruct);
|
||||||
|
CHECK(struct2[1] == testClass->SimpleStruct);
|
||||||
|
CHECK(objects.Count() == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Test Event")
|
SECTION("Test Event")
|
||||||
{
|
{
|
||||||
ScriptingTypeHandle type = Scripting::FindScriptingType("FlaxEngine.TestClassManaged");
|
ScriptingTypeHandle type = Scripting::FindScriptingType("FlaxEngine.TestClassManaged");
|
||||||
CHECK(type);
|
CHECK(type);
|
||||||
ScriptingObject* object = Scripting::NewObject(type.GetType().ManagedClass);
|
ScriptingObject* object = Scripting::NewObject(type);
|
||||||
CHECK(object);
|
CHECK(object);
|
||||||
MObject* managed = object->GetOrCreateManagedInstance(); // Ensure to create C# object and run it's ctor
|
MObject* managed = object->GetOrCreateManagedInstance(); // Ensure to create C# object and run it's ctor
|
||||||
CHECK(managed);
|
CHECK(managed);
|
||||||
@@ -65,12 +79,13 @@ TEST_CASE("Scripting")
|
|||||||
CHECK(arr2[1].Vector == testClass->SimpleStruct.Vector);
|
CHECK(arr2[1].Vector == testClass->SimpleStruct.Vector);
|
||||||
CHECK(arr2[1].Object == testClass);
|
CHECK(arr2[1].Object == testClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Test Interface")
|
SECTION("Test Interface")
|
||||||
{
|
{
|
||||||
// Test native interface implementation
|
// Test native interface implementation
|
||||||
ScriptingTypeHandle type = Scripting::FindScriptingType("FlaxEngine.TestClassNative");
|
ScriptingTypeHandle type = Scripting::FindScriptingType("FlaxEngine.TestClassNative");
|
||||||
CHECK(type);
|
CHECK(type);
|
||||||
ScriptingObject* object = Scripting::NewObject(type.GetType().ManagedClass);
|
ScriptingObject* object = Scripting::NewObject(type);
|
||||||
CHECK(object);
|
CHECK(object);
|
||||||
TestClassNative* testClass = (TestClassNative*)object;
|
TestClassNative* testClass = (TestClassNative*)object;
|
||||||
int32 methodResult = testClass->TestInterfaceMethod(TEXT("123"));
|
int32 methodResult = testClass->TestInterfaceMethod(TEXT("123"));
|
||||||
@@ -86,7 +101,7 @@ TEST_CASE("Scripting")
|
|||||||
// Test managed interface override
|
// Test managed interface override
|
||||||
type = Scripting::FindScriptingType("FlaxEngine.TestClassManaged");
|
type = Scripting::FindScriptingType("FlaxEngine.TestClassManaged");
|
||||||
CHECK(type);
|
CHECK(type);
|
||||||
object = Scripting::NewObject(type.GetType().ManagedClass);
|
object = Scripting::NewObject(type);
|
||||||
CHECK(object);
|
CHECK(object);
|
||||||
testClass = (TestClassNative*)object;
|
testClass = (TestClassNative*)object;
|
||||||
methodResult = testClass->TestInterfaceMethod(TEXT("123"));
|
methodResult = testClass->TestInterfaceMethod(TEXT("123"));
|
||||||
@@ -102,7 +117,7 @@ TEST_CASE("Scripting")
|
|||||||
// Test managed interface implementation
|
// Test managed interface implementation
|
||||||
type = Scripting::FindScriptingType("FlaxEngine.TestInterfaceManaged");
|
type = Scripting::FindScriptingType("FlaxEngine.TestInterfaceManaged");
|
||||||
CHECK(type);
|
CHECK(type);
|
||||||
object = Scripting::NewObject(type.GetType().ManagedClass);
|
object = Scripting::NewObject(type);
|
||||||
CHECK(object);
|
CHECK(object);
|
||||||
interface = ScriptingObject::ToInterface<ITestInterface>(object);
|
interface = ScriptingObject::ToInterface<ITestInterface>(object);
|
||||||
CHECK(interface);
|
CHECK(interface);
|
||||||
|
|||||||
@@ -63,10 +63,24 @@ namespace FlaxEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override int TestMethod(string str)
|
public override int TestMethod(string str, ref TestStructPOD pod, TestStruct[] struct1, ref TestStruct[] struct2, out Object[] objects)
|
||||||
{
|
{
|
||||||
|
objects = new Object[3];
|
||||||
|
if (struct1 == null || struct1.Length != 1)
|
||||||
|
return -1;
|
||||||
|
if (struct2 == null || struct2.Length != 1)
|
||||||
|
return -2;
|
||||||
|
if (pod.Vector != Float3.One)
|
||||||
|
return -3;
|
||||||
|
struct2 = new TestStruct[2]
|
||||||
|
{
|
||||||
|
struct1[0],
|
||||||
|
SimpleStruct,
|
||||||
|
};
|
||||||
|
pod.Vector = Float3.Half;
|
||||||
|
|
||||||
// Test C++ base method invocation
|
// Test C++ base method invocation
|
||||||
return str.Length + base.TestMethod(str);
|
return str.Length + base.TestMethod(str, ref pod, struct1, ref struct2, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -17,6 +17,26 @@ API_STRUCT(NoDefault) struct TestStruct : public ISerializable
|
|||||||
API_FIELD() Float3 Vector = Float3::One;
|
API_FIELD() Float3 Vector = Float3::One;
|
||||||
// Ref
|
// Ref
|
||||||
API_FIELD() ScriptingObject* Object = nullptr;
|
API_FIELD() ScriptingObject* Object = nullptr;
|
||||||
|
|
||||||
|
friend bool operator==(const TestStruct& lhs, const TestStruct& rhs)
|
||||||
|
{
|
||||||
|
return lhs.Vector == rhs.Vector && lhs.Object == rhs.Object;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test structure.
|
||||||
|
API_STRUCT(NoDefault) struct TestStructPOD
|
||||||
|
{
|
||||||
|
DECLARE_SCRIPTING_TYPE_MINIMAL(TestStructPOD);
|
||||||
|
|
||||||
|
// Var
|
||||||
|
API_FIELD() Float3 Vector = Float3::One;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct TIsPODType<TestStructPOD>
|
||||||
|
{
|
||||||
|
enum { Value = true };
|
||||||
};
|
};
|
||||||
|
|
||||||
// Test interface.
|
// Test interface.
|
||||||
@@ -46,7 +66,7 @@ public:
|
|||||||
API_EVENT() Delegate<int32, Float3, const String&, String&, const Array<TestStruct>&, Array<TestStruct>&> SimpleEvent;
|
API_EVENT() Delegate<int32, Float3, const String&, String&, const Array<TestStruct>&, Array<TestStruct>&> SimpleEvent;
|
||||||
|
|
||||||
// Test virtual method
|
// Test virtual method
|
||||||
API_FUNCTION() virtual int32 TestMethod(const String& str)
|
API_FUNCTION() virtual int32 TestMethod(const String& str, API_PARAM(Ref) TestStructPOD& pod, const Array<TestStruct>& struct1, API_PARAM(Ref) Array<TestStruct>& struct2, API_PARAM(Out) Array<ScriptingObject*>& objects)
|
||||||
{
|
{
|
||||||
return str.Length();
|
return str.Length();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -274,6 +274,16 @@ namespace Flax.Build.Bindings
|
|||||||
// Find across in-build types
|
// Find across in-build types
|
||||||
if (InBuildTypes.TryGetValue(typeInfo, out result))
|
if (InBuildTypes.TryGetValue(typeInfo, out result))
|
||||||
return result;
|
return result;
|
||||||
|
if (typeInfo.IsRef)
|
||||||
|
{
|
||||||
|
typeInfo.IsRef = false;
|
||||||
|
if (InBuildTypes.TryGetValue(typeInfo, out result))
|
||||||
|
{
|
||||||
|
typeInfo.IsRef = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
typeInfo.IsRef = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Find across all loaded modules for this build
|
// Find across all loaded modules for this build
|
||||||
foreach (var e in buildData.ModulesInfo)
|
foreach (var e in buildData.ModulesInfo)
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ namespace Flax.Build.Bindings
|
|||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GenerateCppWrapperNativeToManagedParam(BuildData buildData, StringBuilder contents, TypeInfo paramType, string paramName, ApiTypeInfo caller, bool isOut, out bool useLocalVar)
|
private static string GenerateCppWrapperNativeToManagedParam(BuildData buildData, StringBuilder contents, TypeInfo paramType, string paramName, ApiTypeInfo caller, bool isRef, out bool useLocalVar)
|
||||||
{
|
{
|
||||||
useLocalVar = false;
|
useLocalVar = false;
|
||||||
var nativeToManaged = GenerateCppWrapperNativeToManaged(buildData, paramType, caller, out var managedTypeAsNative, null);
|
var nativeToManaged = GenerateCppWrapperNativeToManaged(buildData, paramType, caller, out var managedTypeAsNative, null);
|
||||||
@@ -107,7 +107,7 @@ namespace Flax.Build.Bindings
|
|||||||
if (!string.IsNullOrEmpty(nativeToManaged))
|
if (!string.IsNullOrEmpty(nativeToManaged))
|
||||||
{
|
{
|
||||||
result = string.Format(nativeToManaged, paramName);
|
result = string.Format(nativeToManaged, paramName);
|
||||||
if (managedTypeAsNative[managedTypeAsNative.Length - 1] == '*' && !isOut)
|
if (managedTypeAsNative[managedTypeAsNative.Length - 1] == '*' && !isRef)
|
||||||
{
|
{
|
||||||
// Pass pointer value
|
// Pass pointer value
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,7 @@ namespace Flax.Build.Bindings
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
result = paramName;
|
result = paramName;
|
||||||
if (paramType.IsRef && !paramType.IsConst && !isOut)
|
if (paramType.IsRef && !paramType.IsConst && !isRef)
|
||||||
{
|
{
|
||||||
// Pass reference as a pointer
|
// Pass reference as a pointer
|
||||||
result = '&' + result;
|
result = '&' + result;
|
||||||
@@ -158,13 +158,13 @@ namespace Flax.Build.Bindings
|
|||||||
{
|
{
|
||||||
var wrapperName = GenerateCppWrapperNativeToVariantMethodName(typeInfo);
|
var wrapperName = GenerateCppWrapperNativeToVariantMethodName(typeInfo);
|
||||||
CppVariantFromTypes[wrapperName] = typeInfo;
|
CppVariantFromTypes[wrapperName] = typeInfo;
|
||||||
return $"VariantFrom{GenerateCppWrapperNativeToVariantMethodName(typeInfo)}Array({value}, {typeInfo.ArraySize})";
|
return $"VariantFrom{GenerateCppWrapperNativeToVariantMethodName(typeInfo)}Array((const {typeInfo}*){value}, {typeInfo.ArraySize})";
|
||||||
}
|
}
|
||||||
if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null)
|
if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null)
|
||||||
{
|
{
|
||||||
var wrapperName = GenerateCppWrapperNativeToVariantMethodName(typeInfo.GenericArgs[0]);
|
var wrapperName = GenerateCppWrapperNativeToVariantMethodName(typeInfo.GenericArgs[0]);
|
||||||
CppVariantFromTypes[wrapperName] = typeInfo;
|
CppVariantFromTypes[wrapperName] = typeInfo;
|
||||||
return $"VariantFrom{wrapperName}Array({value}.Get(), {value}.Count())";
|
return $"VariantFrom{wrapperName}Array((const {typeInfo.GenericArgs[0]}*){value}.Get(), {value}.Count())";
|
||||||
}
|
}
|
||||||
if (typeInfo.Type == "Dictionary" && typeInfo.GenericArgs != null)
|
if (typeInfo.Type == "Dictionary" && typeInfo.GenericArgs != null)
|
||||||
{
|
{
|
||||||
@@ -826,10 +826,10 @@ namespace Flax.Build.Bindings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GenerateCppWrapperNativeToBox(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller, string value)
|
private static string GenerateCppWrapperNativeToBox(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller, out ApiTypeInfo apiType, string value)
|
||||||
{
|
{
|
||||||
// Optimize passing scripting objects
|
// Optimize passing scripting objects
|
||||||
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
|
apiType = FindApiTypeInfo(buildData, typeInfo, caller);
|
||||||
if (apiType != null && apiType.IsScriptingObject)
|
if (apiType != null && apiType.IsScriptingObject)
|
||||||
return $"ScriptingObject::ToManaged((ScriptingObject*){value})";
|
return $"ScriptingObject::ToManaged((ScriptingObject*){value})";
|
||||||
|
|
||||||
@@ -1291,6 +1291,8 @@ namespace Flax.Build.Bindings
|
|||||||
contents.Append(')');
|
contents.Append(')');
|
||||||
contents.AppendLine();
|
contents.AppendLine();
|
||||||
contents.AppendLine(" {");
|
contents.AppendLine(" {");
|
||||||
|
|
||||||
|
// Get object
|
||||||
string scriptVTableOffset;
|
string scriptVTableOffset;
|
||||||
if (classInfo.IsInterface)
|
if (classInfo.IsInterface)
|
||||||
{
|
{
|
||||||
@@ -1310,6 +1312,7 @@ namespace Flax.Build.Bindings
|
|||||||
}
|
}
|
||||||
contents.AppendLine(" static THREADLOCAL void* WrapperCallInstance = nullptr;");
|
contents.AppendLine(" static THREADLOCAL void* WrapperCallInstance = nullptr;");
|
||||||
|
|
||||||
|
// Base method call
|
||||||
contents.AppendLine(" ScriptingTypeHandle managedTypeHandle = object->GetTypeHandle();");
|
contents.AppendLine(" ScriptingTypeHandle managedTypeHandle = object->GetTypeHandle();");
|
||||||
contents.AppendLine(" const ScriptingType* managedTypePtr = &managedTypeHandle.GetType();");
|
contents.AppendLine(" const ScriptingType* managedTypePtr = &managedTypeHandle.GetType();");
|
||||||
contents.AppendLine(" while (managedTypePtr->Script.Spawn != &ManagedBinaryModule::ManagedObjectSpawn)");
|
contents.AppendLine(" while (managedTypePtr->Script.Spawn != &ManagedBinaryModule::ManagedObjectSpawn)");
|
||||||
@@ -1317,97 +1320,175 @@ namespace Flax.Build.Bindings
|
|||||||
contents.AppendLine(" managedTypeHandle = managedTypePtr->GetBaseType();");
|
contents.AppendLine(" managedTypeHandle = managedTypePtr->GetBaseType();");
|
||||||
contents.AppendLine(" managedTypePtr = &managedTypeHandle.GetType();");
|
contents.AppendLine(" managedTypePtr = &managedTypeHandle.GetType();");
|
||||||
contents.AppendLine(" }");
|
contents.AppendLine(" }");
|
||||||
|
|
||||||
contents.AppendLine(" if (WrapperCallInstance == object)");
|
contents.AppendLine(" if (WrapperCallInstance == object)");
|
||||||
contents.AppendLine(" {");
|
contents.AppendLine(" {");
|
||||||
GenerateCppVirtualWrapperCallBaseMethod(buildData, contents, classInfo, functionInfo, "managedTypePtr->Script.ScriptVTableBase", scriptVTableOffset);
|
GenerateCppVirtualWrapperCallBaseMethod(buildData, contents, classInfo, functionInfo, "managedTypePtr->Script.ScriptVTableBase", scriptVTableOffset);
|
||||||
contents.AppendLine(" }");
|
contents.AppendLine(" }");
|
||||||
|
|
||||||
contents.AppendLine(" auto scriptVTable = (MMethod**)managedTypePtr->Script.ScriptVTable;");
|
contents.AppendLine(" auto scriptVTable = (MMethod**)managedTypePtr->Script.ScriptVTable;");
|
||||||
contents.AppendLine($" ASSERT(scriptVTable && scriptVTable[{scriptVTableOffset}]);");
|
contents.AppendLine($" ASSERT(scriptVTable && scriptVTable[{scriptVTableOffset}]);");
|
||||||
contents.AppendLine($" auto method = scriptVTable[{scriptVTableOffset}];");
|
contents.AppendLine($" auto method = scriptVTable[{scriptVTableOffset}];");
|
||||||
contents.AppendLine($" PROFILE_CPU_NAMED(\"{classInfo.FullNameManaged}::{functionInfo.Name}\");");
|
|
||||||
contents.AppendLine(" MonoObject* exception = nullptr;");
|
|
||||||
|
|
||||||
|
contents.AppendLine($" PROFILE_CPU_NAMED(\"{classInfo.FullNameManaged}::{functionInfo.Name}\");");
|
||||||
|
|
||||||
|
contents.AppendLine(" MonoObject* exception = nullptr;");
|
||||||
contents.AppendLine(" auto prevWrapperCallInstance = WrapperCallInstance;");
|
contents.AppendLine(" auto prevWrapperCallInstance = WrapperCallInstance;");
|
||||||
contents.AppendLine(" WrapperCallInstance = object;");
|
contents.AppendLine(" WrapperCallInstance = object;");
|
||||||
contents.AppendLine("#if USE_MONO_AOT");
|
|
||||||
|
|
||||||
if (functionInfo.Parameters.Count == 0)
|
if (functionInfo.Parameters.Count == 0)
|
||||||
contents.AppendLine(" void** params = nullptr;");
|
contents.AppendLine(" void** params = nullptr;");
|
||||||
else
|
else
|
||||||
contents.AppendLine($" void* params[{functionInfo.Parameters.Count}];");
|
contents.AppendLine($" void* params[{functionInfo.Parameters.Count}];");
|
||||||
|
|
||||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
// If platform supports JITed code execution then use method thunk, otherwise fallback to generic mono_runtime_invoke
|
||||||
{
|
|
||||||
var parameterInfo = functionInfo.Parameters[i];
|
|
||||||
var paramValue = GenerateCppWrapperNativeToManagedParam(buildData, contents, parameterInfo.Type, parameterInfo.Name, classInfo, parameterInfo.IsOut, out _);
|
|
||||||
contents.Append($" params[{i}] = {paramValue};").AppendLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
contents.AppendLine(" auto __result = mono_runtime_invoke(method->GetNative(), object->GetOrCreateManagedInstance(), params, &exception);");
|
|
||||||
contents.AppendLine("#else");
|
|
||||||
|
|
||||||
var thunkParams = string.Empty;
|
|
||||||
var thunkCall = string.Empty;
|
|
||||||
separator = functionInfo.Parameters.Count != 0;
|
|
||||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
|
||||||
{
|
|
||||||
var parameterInfo = functionInfo.Parameters[i];
|
|
||||||
if (separator)
|
|
||||||
thunkParams += ", ";
|
|
||||||
if (separator)
|
|
||||||
thunkCall += ", ";
|
|
||||||
separator = true;
|
|
||||||
thunkParams += "void*";
|
|
||||||
|
|
||||||
// Mono thunk call uses boxed values as objects
|
|
||||||
thunkCall += GenerateCppWrapperNativeToBox(buildData, parameterInfo.Type, classInfo, parameterInfo.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
var returnType = functionInfo.ReturnType;
|
var returnType = functionInfo.ReturnType;
|
||||||
if (returnType.IsVoid)
|
var useThunk = buildData.Platform.HasDynamicCodeExecutionSupport;
|
||||||
|
if (useThunk)
|
||||||
{
|
{
|
||||||
contents.AppendLine($" typedef void (*Thunk)(void* instance{thunkParams}, MonoObject** exception);");
|
// Convert parameters into managed format as boxed values
|
||||||
contents.AppendLine(" const auto thunk = (Thunk)method->GetThunk();");
|
var thunkParams = string.Empty;
|
||||||
contents.AppendLine($" thunk(object->GetOrCreateManagedInstance(){thunkCall}, &exception);");
|
var thunkCall = string.Empty;
|
||||||
|
if (functionInfo.Parameters.Count != 0)
|
||||||
|
{
|
||||||
|
separator = functionInfo.Parameters.Count != 0;
|
||||||
|
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||||
|
{
|
||||||
|
var parameterInfo = functionInfo.Parameters[i];
|
||||||
|
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
|
||||||
|
var paramValue = GenerateCppWrapperNativeToBox(buildData, parameterInfo.Type, classInfo, out var apiType, parameterInfo.Name);
|
||||||
|
var useLocalVar = false;
|
||||||
|
if (paramIsRef)
|
||||||
|
{
|
||||||
|
// Pass as pointer to value when using ref/out parameter
|
||||||
|
contents.Append($" auto __param_{parameterInfo.Name} = {paramValue};").AppendLine();
|
||||||
|
var useLocalVarPointer = !apiType.IsValueType;
|
||||||
|
paramValue = $"{(useLocalVarPointer ? "&" : "")}__param_{parameterInfo.Name}";
|
||||||
|
CppParamsThatNeedConversion[i] = useLocalVarPointer;
|
||||||
|
useLocalVar = true;
|
||||||
|
}
|
||||||
|
CppParamsThatNeedLocalVariable[i] = useLocalVar;
|
||||||
|
|
||||||
|
if (separator)
|
||||||
|
thunkParams += ", ";
|
||||||
|
if (separator)
|
||||||
|
thunkCall += ", ";
|
||||||
|
separator = true;
|
||||||
|
thunkParams += "void*";
|
||||||
|
contents.Append($" params[{i}] = {paramValue};").AppendLine();
|
||||||
|
thunkCall += $"params[{i}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke method thunk
|
||||||
|
if (returnType.IsVoid)
|
||||||
|
{
|
||||||
|
contents.AppendLine($" typedef void (*Thunk)(void* instance{thunkParams}, MonoObject** exception);");
|
||||||
|
contents.AppendLine(" const auto thunk = (Thunk)method->GetThunk();");
|
||||||
|
contents.AppendLine($" thunk(object->GetOrCreateManagedInstance(){thunkCall}, &exception);");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
contents.AppendLine($" typedef MonoObject* (*Thunk)(void* instance{thunkParams}, MonoObject** exception);");
|
||||||
|
contents.AppendLine(" const auto thunk = (Thunk)method->GetThunk();");
|
||||||
|
contents.AppendLine($" auto __result = thunk(object->GetOrCreateManagedInstance(){thunkCall}, &exception);");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert parameter values back from managed to native (could be modified there)
|
||||||
|
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||||
|
{
|
||||||
|
var parameterInfo = functionInfo.Parameters[i];
|
||||||
|
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
|
||||||
|
if (paramIsRef && !parameterInfo.Type.IsConst)
|
||||||
|
{
|
||||||
|
// Unbox from MonoObject*
|
||||||
|
parameterInfo.Type.IsRef = false;
|
||||||
|
var useLocalVarPointer = CppParamsThatNeedConversion[i];
|
||||||
|
var boxedValueCast = useLocalVarPointer ? "*(MonoObject**)" : "(MonoObject*)";
|
||||||
|
contents.Append($" {parameterInfo.Name} = MUtils::Unbox<{parameterInfo.Type}>({boxedValueCast}params[{i}]);").AppendLine();
|
||||||
|
parameterInfo.Type.IsRef = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
contents.AppendLine($" typedef MonoObject* (*Thunk)(void* instance{thunkParams}, MonoObject** exception);");
|
// Convert parameters into managed format as pointers to value
|
||||||
contents.AppendLine(" const auto thunk = (Thunk)method->GetThunk();");
|
if (functionInfo.Parameters.Count != 0)
|
||||||
contents.AppendLine($" auto __result = thunk(object->GetOrCreateManagedInstance(){thunkCall}, &exception);");
|
{
|
||||||
|
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||||
|
{
|
||||||
|
var parameterInfo = functionInfo.Parameters[i];
|
||||||
|
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
|
||||||
|
var paramValue = GenerateCppWrapperNativeToManagedParam(buildData, contents, parameterInfo.Type, parameterInfo.Name, classInfo, paramIsRef, out CppParamsThatNeedLocalVariable[i]);
|
||||||
|
contents.Append($" params[{i}] = {paramValue};").AppendLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke method
|
||||||
|
contents.AppendLine(" auto __result = mono_runtime_invoke(method->GetNative(), object->GetOrCreateManagedInstance(), params, &exception);");
|
||||||
|
|
||||||
|
// Convert parameter values back from managed to native (could be modified there)
|
||||||
|
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||||
|
{
|
||||||
|
var parameterInfo = functionInfo.Parameters[i];
|
||||||
|
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
|
||||||
|
if (paramIsRef && !parameterInfo.Type.IsConst)
|
||||||
|
{
|
||||||
|
// Direct value convert
|
||||||
|
var managedToNative = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, classInfo, out var managedType, out var apiType, null, out _);
|
||||||
|
var passAsParamPtr = managedType.EndsWith("*");
|
||||||
|
var useLocalVarPointer = CppParamsThatNeedConversion[i] && !apiType.IsValueType;
|
||||||
|
var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)params[{i}]" : $"({managedType}{(passAsParamPtr ? "" : "*")})params[{i}]";
|
||||||
|
if (!string.IsNullOrEmpty(managedToNative))
|
||||||
|
{
|
||||||
|
if (!passAsParamPtr)
|
||||||
|
paramValue = '*' + paramValue;
|
||||||
|
paramValue = string.Format(managedToNative, paramValue);
|
||||||
|
}
|
||||||
|
else if (!passAsParamPtr)
|
||||||
|
paramValue = '*' + paramValue;
|
||||||
|
contents.Append($" {parameterInfo.Name} = {paramValue};").AppendLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contents.AppendLine("#endif");
|
|
||||||
contents.AppendLine(" WrapperCallInstance = prevWrapperCallInstance;");
|
contents.AppendLine(" WrapperCallInstance = prevWrapperCallInstance;");
|
||||||
contents.AppendLine(" if (exception)");
|
contents.AppendLine(" if (exception)");
|
||||||
contents.AppendLine(" DebugLog::LogException(exception);");
|
contents.AppendLine(" DebugLog::LogException(exception);");
|
||||||
|
|
||||||
|
// Unpack returned value
|
||||||
if (!returnType.IsVoid)
|
if (!returnType.IsVoid)
|
||||||
{
|
{
|
||||||
if (returnType.IsRef)
|
if (returnType.IsRef)
|
||||||
throw new NotSupportedException($"Passing return value by reference is not supported for virtual API methods. Used on method '{functionInfo}'.");
|
throw new NotSupportedException($"Passing return value by reference is not supported for virtual API methods. Used on method '{functionInfo}'.");
|
||||||
|
if (useThunk)
|
||||||
switch (returnType.Type)
|
|
||||||
{
|
{
|
||||||
case "bool":
|
// Thunk might return value within pointer (eg. as int or boolean)
|
||||||
contents.AppendLine(" return __result != 0;");
|
switch (returnType.Type)
|
||||||
break;
|
{
|
||||||
case "int8":
|
case "bool":
|
||||||
case "int16":
|
contents.AppendLine(" return __result != 0;");
|
||||||
case "int32":
|
break;
|
||||||
case "int64":
|
case "int8":
|
||||||
contents.AppendLine($" return ({returnType.Type})(intptr)__result;");
|
case "int16":
|
||||||
break;
|
case "int32":
|
||||||
case "uint8":
|
case "int64":
|
||||||
case "uint16":
|
contents.AppendLine($" return ({returnType.Type})(intptr)__result;");
|
||||||
case "uint32":
|
break;
|
||||||
case "uint64":
|
case "uint8":
|
||||||
contents.AppendLine($" return ({returnType.Type})(uintptr)__result;");
|
case "uint16":
|
||||||
break;
|
case "uint32":
|
||||||
default:
|
case "uint64":
|
||||||
|
contents.AppendLine($" return ({returnType.Type})(uintptr)__result;");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
contents.AppendLine($" return MUtils::Unbox<{returnType}>(__result);");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// mono_runtime_invoke always returns boxed value as MonoObject*
|
||||||
contents.AppendLine($" return MUtils::Unbox<{returnType}>(__result);");
|
contents.AppendLine($" return MUtils::Unbox<{returnType}>(__result);");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1732,8 +1813,8 @@ namespace Flax.Build.Bindings
|
|||||||
{
|
{
|
||||||
var paramType = eventInfo.Type.GenericArgs[i];
|
var paramType = eventInfo.Type.GenericArgs[i];
|
||||||
var paramName = "arg" + i;
|
var paramName = "arg" + i;
|
||||||
var paramIsOut = paramType.IsRef && !paramType.IsConst;
|
var paramIsRef = paramType.IsRef && !paramType.IsConst;
|
||||||
var paramValue = GenerateCppWrapperNativeToManagedParam(buildData, contents, paramType, paramName, classInfo, paramIsOut, out CppParamsThatNeedConversion[i]);
|
var paramValue = GenerateCppWrapperNativeToManagedParam(buildData, contents, paramType, paramName, classInfo, paramIsRef, out CppParamsThatNeedConversion[i]);
|
||||||
contents.Append($" params[{i}] = {paramValue};").AppendLine();
|
contents.Append($" params[{i}] = {paramValue};").AppendLine();
|
||||||
}
|
}
|
||||||
if (eventInfo.IsStatic)
|
if (eventInfo.IsStatic)
|
||||||
@@ -1746,8 +1827,8 @@ namespace Flax.Build.Bindings
|
|||||||
for (var i = 0; i < paramsCount; i++)
|
for (var i = 0; i < paramsCount; i++)
|
||||||
{
|
{
|
||||||
var paramType = eventInfo.Type.GenericArgs[i];
|
var paramType = eventInfo.Type.GenericArgs[i];
|
||||||
var paramIsOut = paramType.IsRef && !paramType.IsConst;
|
var paramIsRef = paramType.IsRef && !paramType.IsConst;
|
||||||
if (paramIsOut)
|
if (paramIsRef)
|
||||||
{
|
{
|
||||||
// Convert value back from managed to native (could be modified there)
|
// Convert value back from managed to native (could be modified there)
|
||||||
paramType.IsRef = false;
|
paramType.IsRef = false;
|
||||||
|
|||||||
@@ -130,6 +130,11 @@ namespace Flax.Build
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool HasExecutableFileReferenceSupport => false;
|
public virtual bool HasExecutableFileReferenceSupport => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether that platform supports executing native code generated dynamically (JIT), otherwise requires ahead-of-time compilation (AOT).
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool HasDynamicCodeExecutionSupport => true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the executable file extension (including leading dot).
|
/// Gets the executable file extension (including leading dot).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ namespace Flax.Build.Platforms
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override TargetPlatform Target => TargetPlatform.UWP;
|
public override TargetPlatform Target => TargetPlatform.UWP;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool HasDynamicCodeExecutionSupport => false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="UWPPlatform"/> class.
|
/// Initializes a new instance of the <see cref="UWPPlatform"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user