diff --git a/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs b/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs index d63830be5..b0167c024 100644 --- a/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/ApiTypeInfo.cs @@ -22,6 +22,7 @@ namespace Flax.Build.Bindings public string[] Comment; public bool IsInBuild; public bool IsDeprecated; + public string MarshalAs; internal bool IsInited; internal TypedefInfo Instigator; @@ -151,6 +152,7 @@ namespace Flax.Build.Bindings BindingsGenerator.Write(writer, Namespace); BindingsGenerator.Write(writer, Attributes); BindingsGenerator.Write(writer, Comment); + BindingsGenerator.Write(writer, MarshalAs); writer.Write(IsInBuild); writer.Write(IsDeprecated); BindingsGenerator.Write(writer, Tags); @@ -164,6 +166,7 @@ namespace Flax.Build.Bindings Namespace = BindingsGenerator.Read(reader, Namespace); Attributes = BindingsGenerator.Read(reader, Attributes); Comment = BindingsGenerator.Read(reader, Comment); + MarshalAs = BindingsGenerator.Read(reader, MarshalAs); IsInBuild = reader.ReadBoolean(); IsDeprecated = reader.ReadBoolean(); Tags = BindingsGenerator.Read(reader, Tags); diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Api.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Api.cs index fe17d82e0..4a0070710 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Api.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Api.cs @@ -196,6 +196,9 @@ namespace Flax.Build.Bindings var apiType = FindApiTypeInfo(buildData, typeInfo, caller); if (apiType != null) { + if (apiType.MarshalAs != null) + return UsePassByReference(buildData, new TypeInfo(apiType.MarshalAs), caller); + // Skip for scripting objects if (apiType.IsScriptingObject) return false; diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index f399dd67c..c6f4c37ef 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -420,6 +420,8 @@ namespace Flax.Build.Bindings apiTypeParent = apiTypeParent.Parent; } + if (apiType.MarshalAs != null) + return GenerateCSharpManagedToNativeType(buildData, new TypeInfo(apiType.MarshalAs), caller); if (apiType.IsScriptingObject || apiType.IsInterface) return "IntPtr"; } @@ -509,7 +511,11 @@ namespace Flax.Build.Bindings } else { - returnValueType = GenerateCSharpNativeToManaged(buildData, functionInfo.ReturnType, caller); + var apiType = FindApiTypeInfo(buildData, functionInfo.ReturnType, caller); + if (apiType != null && apiType.MarshalAs != null) + returnValueType = GenerateCSharpNativeToManaged(buildData, new TypeInfo(apiType.MarshalAs), caller); + else + returnValueType = GenerateCSharpNativeToManaged(buildData, functionInfo.ReturnType, caller); } #if USE_NETCORE diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs index c2a785c9c..900d04e95 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs @@ -19,7 +19,7 @@ namespace Flax.Build.Bindings partial class BindingsGenerator { private static readonly Dictionary TypeCache = new Dictionary(); - private const int CacheVersion = 19; + private const int CacheVersion = 20; internal static void Write(BinaryWriter writer, string e) { diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index 2552aac77..3aee2cedc 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -582,6 +582,9 @@ namespace Flax.Build.Bindings { CppReferencesFiles.Add(apiType.File); + if (apiType.MarshalAs != null) + return GenerateCppWrapperNativeToManaged(buildData, new TypeInfo(apiType.MarshalAs), caller, out type, functionInfo); + // Scripting Object if (apiType.IsScriptingObject) { @@ -791,6 +794,9 @@ namespace Flax.Build.Bindings if (apiType != null) { + if (apiType.MarshalAs != null) + return GenerateCppWrapperManagedToNative(buildData, new TypeInfo(apiType.MarshalAs), caller, out type, out apiType, functionInfo, out needLocalVariable); + // Scripting Object (for non-pod types converting only, other API converts managed to unmanaged object in C# wrapper code) if (CppNonPodTypesConvertingGeneration && apiType.IsScriptingObject && typeInfo.IsPtr) { @@ -2370,7 +2376,9 @@ namespace Flax.Build.Bindings CppUsedNonPodTypes.Add(structureInfo); contents.AppendLine(" static MObject* Box(void* ptr)"); contents.AppendLine(" {"); - if (structureInfo.IsPod) + if (structureInfo.MarshalAs != null) + contents.AppendLine($" MISSING_CODE(\"Boxing native type {structureInfo.Name} as {structureInfo.MarshalAs}\"); return nullptr;"); // TODO: impl this + else if (structureInfo.IsPod) contents.AppendLine($" return MCore::Object::Box(ptr, {structureTypeNameNative}::TypeInitializer.GetClass());"); else contents.AppendLine($" return MUtils::Box(*({structureTypeNameNative}*)ptr, {structureTypeNameNative}::TypeInitializer.GetClass());"); @@ -2379,7 +2387,9 @@ namespace Flax.Build.Bindings // Unboxing structures from managed object to native data contents.AppendLine(" static void Unbox(void* ptr, MObject* managed)"); contents.AppendLine(" {"); - if (structureInfo.IsPod) + if (structureInfo.MarshalAs != null) + contents.AppendLine($" MISSING_CODE(\"Boxing native type {structureInfo.Name} as {structureInfo.MarshalAs}\");"); // TODO: impl this + else if (structureInfo.IsPod) contents.AppendLine($" Platform::MemoryCopy(ptr, MCore::Object::Unbox(managed), sizeof({structureTypeNameNative}));"); else contents.AppendLine($" *({structureTypeNameNative}*)ptr = ToNative(*({GenerateCppManagedWrapperName(structureInfo)}*)MCore::Object::Unbox(managed));"); @@ -2657,6 +2667,13 @@ namespace Flax.Build.Bindings { if (CppUsedNonPodTypesList.Contains(apiType)) return; + if (apiType is ClassStructInfo classStructInfo) + { + if (classStructInfo.MarshalAs != null) + return; + if (classStructInfo.IsTemplate) + throw new Exception($"Cannot use template type '{classStructInfo}' as non-POD type for cross-language bindings."); + } if (apiType is StructureInfo structureInfo) { // Check all fields (if one of them is also non-POD structure then we need to generate wrappers for them too) @@ -2679,11 +2696,6 @@ namespace Flax.Build.Bindings } } } - if (apiType is ClassStructInfo classStructInfo) - { - if (classStructInfo.IsTemplate) - throw new Exception($"Cannot use template type '{classStructInfo}' as non-POD type for cross-language bindings."); - } CppUsedNonPodTypesList.Add(apiType); } diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs index d4fcd9629..e187724af 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Parsing.cs @@ -628,6 +628,9 @@ namespace Flax.Build.Bindings case "namespace": desc.Namespace = tag.Value; break; + case "marshalas": + desc.MarshalAs = tag.Value; + break; case "tag": ParseTag(ref desc.Tags, tag); break; @@ -1202,6 +1205,9 @@ namespace Flax.Build.Bindings case "namespace": desc.Namespace = tag.Value; break; + case "marshalas": + desc.MarshalAs = tag.Value; + break; case "tag": ParseTag(ref desc.Tags, tag); break;