public override void OnInspectorGUI() { EditorGUI.BeginDisabledGroup(true); DrawDefaultInspector(); EditorGUI.EndDisabledGroup(); HullPainterChild child = target as HullPainterChild; if (child.parent != null) { Hull sourceHull = child.parent.FindSourceHull(child); if (sourceHull != null) { EditorGUI.BeginDisabledGroup(true); EditorGUILayout.TextField("Source Hull", sourceHull.name); EditorGUI.EndDisabledGroup(); } else { EditorGUILayout.LabelField("No souce hull for this child"); } } else { EditorGUILayout.LabelField("Missing parent!"); } }
private void AddMapping(Hull hull, Collider col, HullPainterChild painterChild) { HullMapping newMapping = new HullMapping() { sourceHull = hull, generatedCollider = col, targetChild = painterChild }; this.hullMapping.Add(newMapping); }
/** Gui drawn if the selected object does not have a valid and initialised hull painter on it */ private void DrawInactiveGui() { if (Selection.transforms.Length == 1) { // Have a single scene selection, is it viable? GameObject selectedObject = Selection.transforms[0].gameObject; MeshFilter srcMesh = SelectionUtil.FindSelectedMeshFilter(); HullPainterChild child = SelectionUtil.FindSelectedHullPainterChild(); if (srcMesh != null) { GUILayout.Space(10); GUILayout.Label("Generate an asset to start painting:"); CommonUi.DrawGenerateOrReconnectGui(selectedObject, srcMesh.sharedMesh); } else if (child != null) { GUILayout.Space(10); GUILayout.Label("Child hulls are not edited directly - select the parent to continue painting this hull"); } else { // No mesh filter, might have a hull painter (or not) GUILayout.Space(10); GUILayout.Label("To start painting, select a single scene object"); GUILayout.Label("The object must contain a MeshFilter"); GUILayout.Space(10); GUILayout.Label("No MeshFilter on selected object", EditorStyles.centeredGreyMiniLabel); } } else { // No single scene selection // Could be nothing selected // Could be multiple selection // Could be an asset in the project selected GUILayout.Space(10); GUILayout.Label("To start painting, select a single scene object"); GUILayout.Label("The object must contain a MeshFilter"); if (GUILayout.Button("Open quick start guide")) { string projectPath = Application.dataPath.Replace("Assets", ""); string docsPdf = projectPath + FindInstallPath() + "Technie Collider Creator Readme.pdf"; Application.OpenURL(docsPdf); } } }
public static HullPainterChild FindSelectedHullPainterChild() { // Works for components in the scene, causes NPEs for selected prefabs in the assets dir if (Selection.transforms.Length == 1) { GameObject currentSelection = Selection.transforms[0].gameObject; HullPainterChild painter = currentSelection.GetComponent <HullPainterChild>(); if (painter != null) { return(painter); } } return(null); }
private HullMapping FindMapping(HullPainterChild child) { if (hullMapping == null) { return(null); } foreach (HullMapping h in hullMapping) { if (h.targetChild == child) { return(h); } } return(null); }
private bool IsMapped(HullPainterChild child) { if (hullMapping == null) { return(false); } foreach (HullMapping map in hullMapping) { if (map.targetChild == child) { return(true); } } return(false); }
public Hull FindSourceHull(HullPainterChild child) { if (hullMapping == null) { // TODO: Hull mapping should be serialised, when it is remove this message as it'll only exist to catch un-upgraded assets // Debug.LogError("No hull mapping present!"); return(null); } foreach (HullMapping h in hullMapping) { if (h.targetChild == child) { return(h.sourceHull); } } return(null); }
private void CreateCollider <T>(Hull sourceHull) where T : Collider { if (sourceHull.isChildCollider) { // GameObject newChild = new GameObject(sourceHull.name); GameObject newChild = CreateGameObject(sourceHull.name); newChild.transform.SetParent(this.transform, false); newChild.transform.localPosition = Vector3.zero; newChild.transform.localRotation = Quaternion.identity; newChild.transform.localScale = Vector3.one; HullPainterChild childPainter = AddComponent <HullPainterChild>(newChild); childPainter.parent = this; T col = AddComponent <T>(newChild); AddMapping(sourceHull, col, childPainter); } else { T col = AddComponent <T>(this.gameObject); AddMapping(sourceHull, col, null); } }
private void CreateHullMapping() { if (hullMapping == null) { // hullMapping = new Dictionary<Hull, Collider>(); hullMapping = new List <HullMapping>(); } // Remove any invalid entries from the hull mapping // null entries are garbage and can be dropped // null source hull means the hull has been deleted and this mapping is no longer relevant // missing *both* generated collider *and* target child means there's no data to point at, so might as well remove it and regen from scratch for (int i = hullMapping.Count - 1; i >= 0; i--) { HullMapping mapping = hullMapping[i]; if (mapping == null || mapping.sourceHull == null || (mapping.generatedCollider == null && mapping.targetChild == null)) { hullMapping.RemoveAt(i); } } // Check to see if any existing mappings need updating (hull.type doesn't match Collider type, or child type no longer matches) foreach (Hull hull in paintingData.hulls) { if (IsMapped(hull)) { // We already have a mapping for this, but is it still of the correct type? Collider value = FindExistingCollider(hullMapping, hull); bool isHullOk = (hull.type == HullType.ConvexHull && value is MeshCollider); bool isBoxOk = (hull.type == HullType.Box && value is BoxCollider); bool isSphereOk = (hull.type == HullType.Sphere && value is SphereCollider); bool isFaceOk = (hull.type == HullType.Face && value is MeshCollider); bool isColliderTypeOk = (isHullOk || isBoxOk || isSphereOk || isFaceOk); bool isChildTypeOk = value == null || ((hull.isChildCollider) == (value.transform.parent == this.transform)); if (isColliderTypeOk && isChildTypeOk) { // All good } else { // Mismatch - hull.type doesn't match collider type // Delete the collider and remove the mapping // This hull will then be orphaned, and a new collider added back in accordingly DestroyImmediateWithUndo(value); RemoveMapping(hull); } } } // Connect orphans // // Find hulls without a Collider // Find Colliders without hulls // Try and map the two together // First find orphans - hull, colliders or childs that aren't already mapped List <Hull> orphanedHulls = new List <Hull>(); List <Collider> orphanedColliders = new List <Collider>(); List <HullPainterChild> orphanedChilds = new List <HullPainterChild>(); foreach (Hull h in paintingData.hulls) { if (!IsMapped(h)) { orphanedHulls.Add(h); } } foreach (Collider c in FindLocal <Collider>()) { if (!IsMapped(c)) { orphanedColliders.Add(c); } } foreach (HullPainterChild c in FindLocal <HullPainterChild>()) { if (!IsMapped(c)) { orphanedChilds.Add(c); } } // Try and connect orphaned hulls with orphaned colliders for (int i = orphanedHulls.Count - 1; i >= 0; i--) { Hull h = orphanedHulls[i]; for (int j = orphanedColliders.Count - 1; j >= 0; j--) { Collider c = orphanedColliders[j]; // Find the HullPainterChild adjacent to the collider (if a child collider) HullPainterChild child = null; if (c.transform.parent == this.transform) { child = c.gameObject.GetComponent <HullPainterChild>(); } // todo needs better handling bool isMatchingChild = h.isChildCollider && c.transform.parent == this.transform; if (isMatchingChild) { BoxCollider boxCol = c as BoxCollider; SphereCollider sphereCol = c as SphereCollider; MeshCollider meshCol = c as MeshCollider; bool isMatchingBox = h.type == HullType.Box && c is BoxCollider && Approximately(h.collisionBox.center, boxCol.center) && Approximately(h.collisionBox.size, boxCol.size); bool isMatchingSphere = h.type == HullType.Sphere && c is SphereCollider && h.collisionSphere != null && Approximately(h.collisionSphere.center, sphereCol.center) && Approximately(h.collisionSphere.radius, sphereCol.radius); bool isMatchingConvexHull = h.type == HullType.ConvexHull && c is MeshCollider && meshCol.sharedMesh == h.collisionMesh; bool isMatchingFace = h.type == HullType.Face && c is MeshCollider && meshCol.sharedMesh == h.faceCollisionMesh; if (isMatchingBox || isMatchingSphere || isMatchingConvexHull || isMatchingFace) { // Found a pair, so add a mapping and remove the orphans AddMapping(h, c, child); // These are no longer orphaned, so remove them from these lists orphanedHulls.RemoveAt(i); orphanedColliders.RemoveAt(j); // Remove the no-longer orphaned child for (int k = 0; k < orphanedChilds.Count; k++) { if (orphanedChilds[k] == child) { orphanedChilds.RemoveAt(k); break; } } break; } } } } // We've tried to connect hulls to existing colliders, now try and connect hulls to existing HullPainterChilds // These will be child without a collider (as otherwise they'd have be picked up earlier) for (int i = orphanedHulls.Count - 1; i >= 0; i--) { Hull h = orphanedHulls[i]; if (!h.isChildCollider) { continue; } for (int j = orphanedChilds.Count - 1; j >= 0; j--) { HullPainterChild child = orphanedChilds[j]; HullMapping mapping = FindMapping(child); if (mapping != null && mapping.sourceHull != null) { // Found a match for hull-mapping-child // Ensure this still has a collider if (mapping.generatedCollider == null) { // Recreate the collider of the correct type with the existing hull-mapping-child RecreateChildCollider(mapping); } orphanedHulls.RemoveAt(i); orphanedChilds.RemoveAt(j); break; } } } // Create colliders for any hull mapping children without colliders foreach (HullMapping mapping in hullMapping) { if (mapping.targetChild != null && mapping.generatedCollider == null) { RecreateChildCollider(mapping); } } // Create child components for child colliders without them foreach (HullMapping mapping in hullMapping) { if (mapping.targetChild == null && mapping.generatedCollider != null && mapping.generatedCollider.transform.parent == this.transform) { // Mapping has a child collider but no HullPainterChild // Recreate the child component HullPainterChild newChild = AddComponent <HullPainterChild>(mapping.generatedCollider.gameObject); newChild.parent = this; mapping.targetChild = newChild; } } // Create colliders for any left over hulls foreach (Hull h in orphanedHulls) { if (h.type == HullType.Box) { CreateCollider <BoxCollider>(h); } else if (h.type == HullType.Sphere) { CreateCollider <SphereCollider>(h); } else if (h.type == HullType.ConvexHull) { CreateCollider <MeshCollider>(h); } else if (h.type == HullType.Face) { CreateCollider <MeshCollider>(h); } } // Delete any left over colliders // TODO: This probably isn't properly undo-aware foreach (Collider c in orphanedColliders) { if (c.gameObject == this.gameObject) { DestroyImmediateWithUndo(c); } else { // Child collider - delete collider, HullPainterChild (if any) and GameObject (if empty) GameObject go = c.gameObject; DestroyImmediateWithUndo(c); DestroyImmediateWithUndo(go.GetComponent <HullPainterChild>()); if (IsDeletable(go)) { DestroyImmediateWithUndo(go); } } } // Delete any left over hull painter childs // TODO: This probably isn't undo-aware foreach (HullPainterChild child in orphanedChilds) { if (child == null) { continue; } // Delete child, collider (if any) and GameObject (if empty) GameObject go = child.gameObject; DestroyImmediateWithUndo(child); DestroyImmediateWithUndo(go.GetComponent <Collider>()); if (IsDeletable(go)) { DestroyImmediateWithUndo(go); } } // Sanity check - all hull mappings should have a collider of the right type now // foreach (HullMapping mapping in hullMapping) // { // if (mapping.generatedCollider == null) // Debug.LogWarning("Null collider for hull: " + mapping.sourceHull.name); // } }