Skip to content

Commit 699d7ac

Browse files
committed
Merge remote-tracking branch 'refs/remotes/origin/master' into UNI-24204-zip-maya-integration
# Conflicts: # Assets/FbxExporters/Editor/InstallIntegration.cs
2 parents 72e804d + f75d07a commit 699d7ac

24 files changed

+652
-190
lines changed

Assets/FbxExporters/Editor/FbxExportSettings.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@ public override void OnInspectorGUI() {
9898
);
9999

100100
GUILayout.EndHorizontal ();
101+
102+
EditorGUILayout.Space ();
103+
if (GUILayout.Button (new GUIContent ("Auto Review",
104+
"Opens turntable review of last saved prefab."))) {
105+
FbxExporters.Review.TurnTable.LastSavedModel ();
106+
}
107+
108+
EditorGUILayout.Space ();
109+
if (GUILayout.Button ("Install Maya Integration")) {
110+
FbxExporters.Editor.IntegrationsUI.InstallMayaIntegration ();
111+
}
112+
101113
GUILayout.FlexibleSpace ();
102114
GUILayout.EndScrollView ();
103115

Assets/FbxExporters/Editor/FbxExporter.cs

Lines changed: 181 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,24 +1353,192 @@ private static GameObject GetGameObject (Object obj)
13531353
}
13541354

13551355
/// <summary>
1356-
/// Get a mesh renderer's mesh.
1356+
/// If your MonoBehaviour knows about some custom geometry that
1357+
/// isn't in a MeshFilter or SkinnedMeshRenderer, use
1358+
/// RegisterMeshCallback to get a callback when the exporter tries
1359+
/// to export your component.
1360+
///
1361+
/// The callback should return true, and output the mesh you want.
1362+
///
1363+
/// Return false if you don't want to drive this game object.
1364+
///
1365+
/// Return true and output a null mesh if you don't want the
1366+
/// exporter to output anything.
13571367
/// </summary>
1358-
private MeshInfo GetMeshInfo (GameObject gameObject, bool requireRenderer = true)
1368+
public delegate bool GetMeshForComponent<T>(T component, out Mesh mesh) where T : MonoBehaviour;
1369+
public delegate bool GetMeshForComponent(MonoBehaviour component, out Mesh mesh);
1370+
1371+
/// <summary>
1372+
/// Map from type (must be a MonoBehaviour) to callback.
1373+
/// The type safety is lost; the caller must ensure it at run-time.
1374+
/// </summary>
1375+
static Dictionary<System.Type, GetMeshForComponent> MeshForComponentCallbacks
1376+
= new Dictionary<System.Type, GetMeshForComponent>();
1377+
1378+
/// <summary>
1379+
/// Register a callback to invoke if the object has a component of type T.
1380+
///
1381+
/// This function is prefered over the other mesh callback
1382+
/// registration methods because it's type-safe, efficient, and
1383+
/// invocation order between types can be controlled in the UI by
1384+
/// reordering the components.
1385+
///
1386+
/// It's an error to register a callback for a component that
1387+
/// already has one, unless 'replace' is set to true.
1388+
/// </summary>
1389+
public static void RegisterMeshCallback<T>(GetMeshForComponent<T> callback, bool replace = false)
1390+
where T: UnityEngine.MonoBehaviour
13591391
{
1360-
// Two possibilities: it's a skinned mesh, or we have a mesh filter.
1361-
Mesh mesh;
1362-
var meshFilter = gameObject.GetComponent<MeshFilter> ();
1363-
if (meshFilter) {
1364-
mesh = meshFilter.sharedMesh;
1365-
} else {
1366-
var renderer = gameObject.GetComponent<SkinnedMeshRenderer> ();
1367-
if (!renderer) {
1368-
mesh = null;
1392+
// Under the hood we lose type safety, but don't let the user notice!
1393+
RegisterMeshCallback(typeof(T),
1394+
(MonoBehaviour component, out Mesh mesh) => callback((T)component, out mesh),
1395+
replace);
1396+
}
1397+
1398+
/// <summary>
1399+
/// Register a callback to invoke if the object has a component of type T.
1400+
///
1401+
/// The callback will be invoked with an argument of type T, it's
1402+
/// safe to downcast.
1403+
///
1404+
/// Normally you'll want to use the generic form, but this one is
1405+
/// easier to use with reflection.
1406+
/// </summary>
1407+
public static void RegisterMeshCallback(System.Type t,
1408+
GetMeshForComponent callback,
1409+
bool replace = false)
1410+
{
1411+
if (!t.IsSubclassOf(typeof(MonoBehaviour))) {
1412+
throw new System.Exception("Registering a callback for a type that isn't derived from MonoBehaviour: " + t);
1413+
}
1414+
if (!replace && MeshForComponentCallbacks.ContainsKey(t)) {
1415+
throw new System.Exception("Replacing a callback for type " + t);
1416+
}
1417+
MeshForComponentCallbacks[t] = callback;
1418+
}
1419+
1420+
/// <summary>
1421+
/// Delegate used to convert a GameObject into a mesh.
1422+
///
1423+
/// This is useful if you want to have broader control over
1424+
/// the export process than the GetMeshForComponent callbacks
1425+
/// provide. But it's less efficient because you'll get a callback
1426+
/// on every single GameObject.
1427+
/// </summary>
1428+
public delegate bool GetMeshForObject(GameObject gameObject, out Mesh mesh);
1429+
1430+
static List<GetMeshForObject> MeshForObjectCallbacks = new List<GetMeshForObject>();
1431+
1432+
/// <summary>
1433+
/// Register a callback to invoke on every GameObject we export.
1434+
///
1435+
/// Avoid doing this if you can use a callback that depends on type.
1436+
///
1437+
/// The GameObject-based callbacks are checked before the
1438+
/// component-based ones.
1439+
///
1440+
/// Multiple GameObject-based callbacks can be registered; they are
1441+
/// checked in order of registration.
1442+
/// </summary>
1443+
public static void RegisterMeshObjectCallback(GetMeshForObject callback)
1444+
{
1445+
MeshForObjectCallbacks.Add(callback);
1446+
}
1447+
1448+
/// <summary>
1449+
/// Forget the callback linked to a component of type T.
1450+
/// </summary>
1451+
public static void UnRegisterMeshCallback<T>()
1452+
{
1453+
MeshForComponentCallbacks.Remove(typeof(T));
1454+
}
1455+
1456+
/// <summary>
1457+
/// Forget the callback linked to a component of type T.
1458+
/// </summary>
1459+
public static void UnRegisterMeshCallback(System.Type t)
1460+
{
1461+
MeshForComponentCallbacks.Remove(t);
1462+
}
1463+
1464+
/// <summary>
1465+
/// Forget a GameObject-based callback.
1466+
/// </summary>
1467+
public static void UnRegisterMeshCallback(GetMeshForObject callback)
1468+
{
1469+
MeshForObjectCallbacks.Remove(callback);
1470+
}
1471+
1472+
/// <summary>
1473+
/// Get the mesh we want to use for a GameObject.
1474+
/// May be null.
1475+
/// </summary>
1476+
Mesh ChooseMeshForObject(GameObject gameObject)
1477+
{
1478+
// First allow the object-based callbacks to have a hack at it.
1479+
foreach(var callback in MeshForObjectCallbacks) {
1480+
Mesh mesh;
1481+
if (callback(gameObject, out mesh)) {
1482+
return mesh;
1483+
}
1484+
}
1485+
1486+
// Next iterate over components and allow the component-based
1487+
// callbacks to have a hack at it. This is complicated by the
1488+
// potential of subclassing.
1489+
Mesh defaultMesh = null;
1490+
foreach(var component in gameObject.GetComponents<Component>()) {
1491+
if (!component) {
1492+
continue;
1493+
}
1494+
var monoBehaviour = component as MonoBehaviour;
1495+
if (!monoBehaviour) {
1496+
// Check for default handling. But don't commit yet.
1497+
if (defaultMesh) {
1498+
continue;
1499+
}
1500+
var meshFilter = component as MeshFilter;
1501+
if (meshFilter) {
1502+
defaultMesh = (component as MeshFilter).sharedMesh;
1503+
continue;
1504+
}
1505+
var smr = component as SkinnedMeshRenderer;
1506+
if (smr) {
1507+
defaultMesh = new Mesh();
1508+
smr.BakeMesh(defaultMesh);
1509+
continue;
1510+
}
13691511
} else {
1370-
mesh = new Mesh ();
1371-
renderer.BakeMesh (mesh);
1512+
// Check if we have custom behaviour for this component type, or
1513+
// one of its base classes.
1514+
if (!monoBehaviour.enabled) {
1515+
continue;
1516+
}
1517+
var componentType = monoBehaviour.GetType ();
1518+
do {
1519+
GetMeshForComponent callback;
1520+
if (MeshForComponentCallbacks.TryGetValue (componentType, out callback)) {
1521+
Mesh mesh;
1522+
if (callback (monoBehaviour, out mesh)) {
1523+
return mesh;
1524+
}
1525+
}
1526+
componentType = componentType.BaseType;
1527+
} while(componentType.IsSubclassOf (typeof(MonoBehaviour)));
13721528
}
13731529
}
1530+
1531+
// If we're here, custom handling didn't work.
1532+
// Revert to default handling.
1533+
return defaultMesh;
1534+
}
1535+
1536+
/// <summary>
1537+
/// Get the mesh for an object in an easy-to-use format.
1538+
/// </summary>
1539+
private MeshInfo GetMeshInfo (GameObject gameObject)
1540+
{
1541+
var mesh = ChooseMeshForObject(gameObject);
13741542
if (!mesh) {
13751543
return new MeshInfo(null);
13761544
}

0 commit comments

Comments
 (0)