diff --git a/EzySlice/Slicer.cs b/EzySlice/Slicer.cs old mode 100644 new mode 100755 index 73b841f..1b28201 --- a/EzySlice/Slicer.cs +++ b/EzySlice/Slicer.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Collections.Generic; using UnityEngine; @@ -9,6 +10,33 @@ namespace EzySlice { */ public sealed class Slicer { + internal struct SlicedMeshDetails : IEquatable + { + public List crossHull; + public SlicedSubmesh[] slices; + + public bool Equals(SlicedMeshDetails other) + { + throw new NotImplementedException(); + } + }; + + internal struct MeshDetails : IEquatable + { + public bool valid; + public MeshFilter filter; + public MeshRenderer renderer; + public Material[] materials; + public Mesh mesh; + public int submeshCount; + public int crossIndex; + + public bool Equals(MeshDetails other) + { + throw new NotImplementedException(); + } + }; + /** * An internal class for storing internal submesh values */ @@ -66,62 +94,63 @@ public bool isValid { * See -> Slice(Mesh, Plane) for more info */ public static SlicedHull Slice(GameObject obj, Plane pl, TextureRegion crossRegion, Material crossMaterial) { - MeshFilter filter = obj.GetComponent(); - // cannot continue without a proper filter - if (filter == null) { - Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a MeshFilter Component."); + MeshDetails md = GetMeshDetails(obj); + if (!md.valid) + { return null; } - - MeshRenderer renderer = obj.GetComponent(); - - // cannot continue without a proper renderer - if (renderer == null) { - Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a MeshRenderer Component."); - - return null; + + // crossIndex - we need to find the index of the material for the cross section. + // default to the end of the array + // for cases where the sliced material is null, we will append the cross section to the end + // of the submesh array, this is because the application may want to set/change the material + // after slicing has occured, so we don't assume anything + if (crossMaterial != null) { + for (int i = 0; i < md.crossIndex; i++) { + if (md.materials[i] == crossMaterial) { + md.crossIndex = i; + break; + } + } } - Material[] materials = renderer.sharedMaterials; + return Slice(md.mesh, pl, crossRegion, md.crossIndex); + } - Mesh mesh = filter.sharedMesh; - // cannot slice a mesh that doesn't exist - if (mesh == null) { - Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a Mesh that is not NULL."); + // Helper function for edgeloop functionality + public static List EdgeLoop(GameObject obj, Plane pl) { + + MeshDetails md = GetMeshDetails(obj); + if (!md.valid) + { return null; } - int submeshCount = mesh.subMeshCount; - - // to make things straightforward, exit without slicing if the materials and mesh - // array don't match. This shouldn't happen anyway - if (materials.Length != submeshCount) { - Debug.LogWarning("EzySlice::Slice -> Provided Material array must match the length of submeshes."); + return EdgeLoop(md.mesh, pl); + } + private static List EdgeLoop(Mesh sharedMesh, Plane pl) { + if (sharedMesh == null) { return null; } - // we need to find the index of the material for the cross section. - // default to the end of the array - int crossIndex = materials.Length; - - // for cases where the sliced material is null, we will append the cross section to the end - // of the submesh array, this is because the application may want to set/change the material - // after slicing has occured, so we don't assume anything - if (crossMaterial != null) { - for (int i = 0; i < crossIndex; i++) { - if (materials[i] == crossMaterial) { - crossIndex = i; - break; - } + SlicedMeshDetails sliceDetails = SliceMesh(sharedMesh, pl); + + // check if slicing actually occured + for (int i = 0; i < sliceDetails.slices.Length; i++) { + // check if at least one of the submeshes was sliced. If so, stop checking + // because we need to go through the generation step + if (sliceDetails.slices[i] != null && sliceDetails.slices[i].isValid) { + return sliceDetails.crossHull; } } - return Slice(mesh, pl, crossRegion, crossIndex); + // no slicing occured, just return null to signify + return null; } /** @@ -137,6 +166,27 @@ public static SlicedHull Slice(Mesh sharedMesh, Plane pl, TextureRegion region, return null; } + SlicedMeshDetails sliceDetails = SliceMesh(sharedMesh, pl); + + // check if slicing actually occured + for (int i = 0; i < sliceDetails.slices.Length; i++) { + // check if at least one of the submeshes was sliced. If so, stop checking + // because we need to go through the generation step + if (sliceDetails.slices[i] != null && sliceDetails.slices[i].isValid) { + return CreateFrom(sliceDetails.slices, CreateFrom(sliceDetails.crossHull, pl.normal, region), crossIndex); + } + } + + // no slicing occured, just return null to signify + return null; + } + + /** + * Slice the mesh, and return sliced mesh details + **/ + private static SlicedMeshDetails SliceMesh(Mesh sharedMesh, Plane pl) { + + SlicedMeshDetails details = new SlicedMeshDetails(); Vector3[] verts = sharedMesh.vertices; Vector2[] uv = sharedMesh.uv; Vector3[] norm = sharedMesh.normals; @@ -222,17 +272,77 @@ public static SlicedHull Slice(Mesh sharedMesh, Plane pl, TextureRegion region, slices[submesh] = mesh; } - // check if slicing actually occured - for (int i = 0; i < slices.Length; i++) { - // check if at least one of the submeshes was sliced. If so, stop checking - // because we need to go through the generation step - if (slices[i] != null && slices[i].isValid) { - return CreateFrom(slices, CreateFrom(crossHull, pl.normal, region), crossIndex); - } + details.slices = slices; + details.crossHull = crossHull; + return details; + } + + private static bool IsGameObjectOk(GameObject obj) + { + MeshFilter filter = obj.GetComponent(); + + // cannot continue without a proper filter + if (filter == null) { + Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a MeshFilter Component."); + + return false; } - // no slicing occured, just return null to signify - return null; + MeshRenderer renderer = obj.GetComponent(); + + // cannot continue without a proper renderer + if (renderer == null) { + Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a MeshRenderer Component."); + + return false; + } + + Material[] materials = renderer.sharedMaterials; + + Mesh mesh = filter.sharedMesh; + + // cannot slice a mesh that doesn't exist + if (mesh == null) { + Debug.LogWarning("EzySlice::Slice -> Provided GameObject must have a Mesh that is not NULL."); + + return false; + } + + int submeshCount = mesh.subMeshCount; + + // to make things straightforward, exit without slicing if the materials and mesh + // array don't match. This shouldn't happen anyway + if (materials.Length != submeshCount) { + Debug.LogWarning("EzySlice::Slice -> Provided Material array must match the length of submeshes."); + + return false; + } + + return true; + } + + /** + * Return mesh details or null if the supplied gameobject cannot be processed. + */ + private static MeshDetails GetMeshDetails(GameObject obj) + { + MeshDetails md = new MeshDetails(); + + if (!IsGameObjectOk(obj)) + { + md.valid = false; + return md; + } + + md.filter = obj.GetComponent(); + md.renderer = obj.GetComponent(); + md.materials = md.renderer.sharedMaterials; + md.mesh = md.filter.sharedMesh; + md.submeshCount = md.mesh.subMeshCount; + md.crossIndex = md.materials.Length; + md.valid = true; + + return md; } /** diff --git a/EzySlice/SlicerExtensions.cs b/EzySlice/SlicerExtensions.cs old mode 100644 new mode 100755 index 3793dc5..8c26cee --- a/EzySlice/SlicerExtensions.cs +++ b/EzySlice/SlicerExtensions.cs @@ -1,4 +1,5 @@ using System.Collections; +using System.Collections.Generic; using UnityEngine; namespace EzySlice { @@ -6,7 +7,6 @@ namespace EzySlice { * Define Extension methods for easy access to slicer functionality */ public static class SlicerExtensions { - /** * SlicedHull Return functions and appropriate overrides! */ @@ -44,11 +44,12 @@ public static GameObject[] SliceInstantiate(this GameObject obj, Vector3 positio return SliceInstantiate(obj, position, direction, null); } - public static GameObject[] SliceInstantiate(this GameObject obj, Vector3 position, Vector3 direction, Material crossSectionMat) { + public static GameObject[] SliceInstantiate(this GameObject obj, Vector3 position, Vector3 direction, Material crossSectionMat) { return SliceInstantiate(obj, position, direction, new TextureRegion(0.0f, 0.0f, 1.0f, 1.0f), crossSectionMat); } public static GameObject[] SliceInstantiate(this GameObject obj, Vector3 position, Vector3 direction, TextureRegion cuttingRegion, Material crossSectionMaterial = null) { + EzySlice.Plane cuttingPlane = new EzySlice.Plane(); Vector3 refUp = obj.transform.InverseTransformDirection(direction); @@ -82,9 +83,10 @@ public static GameObject[] SliceInstantiate(this GameObject obj, Plane pl, Textu if (lowerHull != null) { return new GameObject[] { lowerHull }; } - + // nothing to return, so return nothing! return null; + } } } \ No newline at end of file