// todo Once we drop support for 2018.3, use optional assembly definitions
using System;
using UnityEditor;
using System.Reflection;
using System.Linq;
using UnityEditor.ProBuilder;
namespace UnityEngine.ProBuilder.Addons.FBX
{
///
/// ProBuilder-specific options when exporting FBX files with the Unity FBX Exporter.
///
class FbxOptions
{
///
/// Export mesh topology as quads if possible.
///
#pragma warning disable 649
public bool quads;
#pragma warning restore 649
}
///
/// Provides some additional functionality when the FbxSdk and FbxExporter packages are available in the project.
///
[InitializeOnLoad]
static class Fbx
{
private static Assembly FbxExporterAssembly
{
get
{
try
{
return Assembly.Load("Unity.Formats.Fbx.Editor");
}
catch (System.IO.FileNotFoundException)
{
return null;
}
}
}
static readonly Type[] k_ProBuilderTypes = new Type[]
{
typeof(BezierShape),
typeof(PolyShape),
typeof(Entity)
};
static FbxOptions m_FbxOptions = new FbxOptions() {
quads = true
};
static Fbx()
{
TryLoadFbxSupport();
}
static void TryLoadFbxSupport()
{
if (FbxExporterAssembly == null)
{
return;
}
var modelExporter = FbxExporterAssembly.GetType("UnityEditor.Formats.Fbx.Exporter.ModelExporter");
var registerMeshCallback = modelExporter.GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Where(x => x.Name == "RegisterMeshCallback").First(x => x.ContainsGenericParameters);
registerMeshCallback = registerMeshCallback.MakeGenericMethod(typeof(ProBuilderMesh));
var getMeshForComponent = FbxExporterAssembly.GetTypes()
.Where(t => t.BaseType == typeof(MulticastDelegate) && t.Name.StartsWith("GetMeshForComponent"))
.First(t => t.ContainsGenericParameters);
getMeshForComponent = getMeshForComponent.MakeGenericType(typeof(ProBuilderMesh));
var meshDelegate = Delegate.CreateDelegate(getMeshForComponent, typeof(Fbx).GetMethod("GetMeshForComponent", BindingFlags.NonPublic | BindingFlags.Static));
registerMeshCallback.Invoke(null, new object[] { meshDelegate, true });
m_FbxOptions.quads = ProBuilderSettings.Get("Export::m_FbxQuads", SettingsScope.User, true);
}
static bool GetMeshForComponent(object exporter, ProBuilderMesh pmesh, object node)
{
Mesh mesh = new Mesh();
MeshUtility.Compile(pmesh, mesh, m_FbxOptions.quads ? MeshTopology.Quads : MeshTopology.Triangles);
// using reflection to call: exporter.ExportMesh(mesh, node, pmesh.GetComponent().sharedMaterials)
var pMeshRenderer = pmesh.GetComponent();
var sharedMaterials = pMeshRenderer ? pMeshRenderer.sharedMaterials : null;
var exportMeshMethod = exporter.GetType().GetMethod("ExportMesh", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(Mesh), node.GetType(), typeof(Material[]) }, null);
exportMeshMethod.Invoke(exporter, new object[] { mesh, node, sharedMaterials });
Object.DestroyImmediate(mesh);
// probuilder can't handle mesh assets that may be externally reloaded, just strip pb stuff for now.
foreach (var type in k_ProBuilderTypes)
{
var component = pmesh.GetComponent(type);
if (component != null)
Object.DestroyImmediate(component);
}
pmesh.preserveMeshAssetOnDestroy = true;
Object.DestroyImmediate(pmesh);
return true;
}
}
}