// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
// for ex. property getter/setter access. To get optimal decompilation results, please manually add the missing references to the list of loaded assemblies.
// EdenAutoMorpherScript, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// Eden.AutoMorpher.MeshMatcher
using Eden.AutoMorpher;
using System.Collections.Generic;
using UnityEngine;

public class MeshMatcher
{
    public struct ClosestHit
    {
        public Vector3 closestP;

        public Vector3 direction;

        public Vector3 moveVector;

        public float distance;
    }

    public BvhTriangleMesh bodyBVH;

    private readonly HashSet<HumanBodyBones> LeftLegBones = new HashSet<HumanBodyBones>
    {
        HumanBodyBones.LeftUpperLeg,
        HumanBodyBones.LeftLowerLeg,
        HumanBodyBones.LeftFoot,
        HumanBodyBones.LeftToes
    };

    private readonly HashSet<HumanBodyBones> RightLegBones = new HashSet<HumanBodyBones>
    {
        HumanBodyBones.RightUpperLeg,
        HumanBodyBones.RightLowerLeg,
        HumanBodyBones.RightFoot,
        HumanBodyBones.RightToes
    };

    public BvhTriangleMesh BuildBvhMulti(IReadOnlyList<SkinnedMeshRenderer> bodies, Animator bodyAnimator)
    {
        if (bodies == null || bodies.Count == 0)
        {
            throw new AutoMorpherException("Body Meshes are Missing", "[BuildBvhMulti] BuildBvhMulti\n - bodies is null or empty");
        }
        BvhTriangleMesh bvhTriangleMesh = new BvhTriangleMesh().BuildFromSkinnedMeshes(bodies, bodyAnimator);
        if (bvhTriangleMesh == null || bvhTriangleMesh.triangles == null)
        {
            Debug.LogError("Failed to build multi-body BVH (no triangles).");
            throw new AutoMorpherException(LanguageManager.Get("UI.Exception.title.BodyBVHFail"), LanguageManager.GetFormat("UI.Exception.message.BodyBVHFail", new object[3]
            {
                bodyAnimator.gameObject.name,
                bvhTriangleMesh == null,
                bvhTriangleMesh.triangles == null
            }));
        }
        return bvhTriangleMesh;
    }

    public Vector3[] ExpandVertexMatch(ClothInstance clothInstance, float defaultMinDist = 0.005f, bool skipFootFitting = false, float maxMatchDistance = 0.1f)
    {
        Vector3[] worldVertices = clothInstance.worldVertices;
        float[] minDistance = clothInstance.minDistance;
        if (this.bodyBVH == null)
        {
            throw new AutoMorpherException("Body BVH is Missing", "[ExpandVertexMatch] ExpandVertexMatch\n - bodyBVH is null");
        }
        if (worldVertices == null)
        {
            throw new AutoMorpherException("Cloth World Vertices are Missing", "[ExpandVertexMatch] ExpandVertexMatch\n - clothInstance.worldVertices is null");
        }
        if (worldVertices.Length == 0)
        {
            Debug.LogWarning("clothes mesh has no vertices");
            return null;
        }
        if (minDistance == null)
        {
            Debug.LogWarning("minDists is null");
        }
        if (minDistance.Length != worldVertices.Length)
        {
            Debug.LogWarning("minDists.Length != worldVertexs.Length");
        }
        Vector3[] array = new Vector3[worldVertices.Length];
        float num = maxMatchDistance * maxMatchDistance;
        for (int i = 0; i < worldVertices.Length; i++)
        {
            if (clothInstance.excludedVertices[i])
            {
                array[i] = Vector3.zero;
                continue;
            }
            if (clothInstance.isInsideVertex[i])
            {
                array[i] = Vector3.zero;
                continue;
            }
            float num2 = minDistance[i] + defaultMinDist;
            BvhTriangleMesh.ClosestHit closestHit = (clothInstance.isLeftLegVertex[i] ? this.bodyBVH.QueryClosest(worldVertices[i], this.LeftLegBones) : ((!clothInstance.isRightLegVertex[i]) ? this.bodyBVH.QueryClosest(worldVertices[i]) : this.bodyBVH.QueryClosest(worldVertices[i], this.RightLegBones)));
            if (skipFootFitting && (closestHit.mainHumanBone == HumanBodyBones.LeftFoot || closestHit.mainHumanBone == HumanBodyBones.RightFoot || closestHit.mainHumanBone == HumanBodyBones.RightToes || closestHit.mainHumanBone == HumanBodyBones.LeftToes))
            {
                array[i] = Vector3.zero;
                continue;
            }
            if (closestHit.sqrDistance > num)
            {
                array[i] = Vector3.zero;
                continue;
            }
            Vector3 normalized = (closestHit.closestPoint - worldVertices[i]).normalized;
            float num3 = Vector3.Dot(normalized, closestHit.normal.normalized);
            if (num3 > 0.7f)
            {
                array[i] = closestHit.closestPoint + normalized * num2 - worldVertices[i];
            }
            else if (num3 < -0.7f)
            {
                if (closestHit.sqrDistance < num2 * num2)
                {
                    array[i] = closestHit.closestPoint - normalized * num2 - worldVertices[i];
                }
            }
            else
            {
                array[i] = Vector3.zero;
            }
        }
        return array;
    }

    public Vector3[] ShrinkVertexMatch(ClothInstance clothInstance, float defaultMinDist = 0.005f, float maxMatchDistance = 0.1f)
    {
        Vector3[] worldVertices = clothInstance.worldVertices;
        float[] minDistance = clothInstance.minDistance;
        if (this.bodyBVH == null)
        {
            throw new AutoMorpherException("Body BVH is Missing", "[ShrinkVertexMatch] ShrinkVertexMatch\n - bodyBVH is null");
        }
        if (worldVertices == null)
        {
            throw new AutoMorpherException("Cloth World Vertices are Missing", "[ShrinkVertexMatch] ShrinkVertexMatch\n - clothInstance.worldVertices is null");
        }
        if (worldVertices.Length == 0)
        {
            Debug.LogWarning("clothes mesh has no vertices");
            return null;
        }
        if (minDistance == null)
        {
            Debug.LogWarning("minDists is null");
        }
        if (minDistance.Length != worldVertices.Length)
        {
            Debug.LogWarning("minDists.Length != worldVertexs.Length");
        }
        Vector3[] array = new Vector3[worldVertices.Length];
        float num = maxMatchDistance * maxMatchDistance;
        _ = clothInstance.isLeftLegVertex;
        _ = clothInstance.isRightLegVertex;
        for (int i = 0; i < worldVertices.Length; i++)
        {
            if (clothInstance.excludedVertices[i])
            {
                array[i] = Vector3.zero;
                continue;
            }
            if (clothInstance.isInsideVertex[i])
            {
                array[i] = Vector3.zero;
                continue;
            }
            float num2 = minDistance[i] + defaultMinDist;
            BvhTriangleMesh.ClosestHit closestHit = (clothInstance.isLeftLegVertex[i] ? this.bodyBVH.QueryClosest(worldVertices[i], this.LeftLegBones) : ((!clothInstance.isRightLegVertex[i]) ? this.bodyBVH.QueryClosest(worldVertices[i]) : this.bodyBVH.QueryClosest(worldVertices[i], this.RightLegBones)));
            if (closestHit.sqrDistance > num)
            {
                array[i] = Vector3.zero;
                continue;
            }
            if (closestHit.mainHumanBone == HumanBodyBones.LeftFoot || closestHit.mainHumanBone == HumanBodyBones.RightFoot || closestHit.mainHumanBone == HumanBodyBones.RightToes || closestHit.mainHumanBone == HumanBodyBones.LeftToes)
            {
                array[i] = Vector3.zero;
                continue;
            }
            Vector3 normalized = (closestHit.closestPoint - worldVertices[i]).normalized;
            float num3 = Vector3.Dot(normalized, closestHit.normal.normalized);
            if (num3 < -0.7f)
            {
                array[i] = closestHit.closestPoint - normalized * num2 - worldVertices[i];
            }
            else if (num3 < -0.7f)
            {
                if (closestHit.sqrDistance < num2 * num2)
                {
                    array[i] = closestHit.closestPoint + normalized * num2 - worldVertices[i];
                }
            }
            else
            {
                array[i] = Vector3.zero;
            }
        }
        return array;
    }

    public Vector3[] GetMinDistanceToBody(Vector3[] clothesVertices)
    {
        if (this.bodyBVH == null)
        {
            throw new AutoMorpherException("sourceBodyBVH is null", "[MeshMatcher] GetMinDistanceToBodysourceBodyBVH is null");
        }
        if (clothesVertices == null || clothesVertices.Length == 0)
        {
            throw new AutoMorpherException("Source Vertices is null", "[MeshMatcher] GetMinDistanceToBodySource Vertices is null or no vertices");
        }
        Vector3[] array = new Vector3[clothesVertices.Length];
        for (int i = 0; i < clothesVertices.Length; i++)
        {
            Vector3 vector = clothesVertices[i];
            Vector3 vector2 = this.bodyBVH.QueryClosest(vector).closestPoint - vector;
            array[i] = vector2;
        }
        return array;
    }

    public bool[] GetBodyInsideFlags(Vector3[] worldVertices)
    {
        if (this.bodyBVH == null)
        {
            throw new AutoMorpherException("sourceBodyBVH is null", "[MeshMatcher] GetBodyInsideFlagssourceBodyBVH is null");
        }
        if (worldVertices == null || worldVertices.Length == 0)
        {
            Debug.LogError("clothes is null");
            throw new AutoMorpherException("Source Vertices is null", "[MeshMatcher] GetMinDistanceToBodySource Vertices is null or no vertices");
        }
        bool[] array = new bool[worldVertices.Length];
        for (int i = 0; i < worldVertices.Length; i++)
        {
            BvhTriangleMesh.ClosestHit closestHit = this.bodyBVH.QueryClosest(worldVertices[i]);
            float num = Vector3.Dot((closestHit.closestPoint - worldVertices[i]).normalized, closestHit.normal.normalized);
            array[i] = num > 0f;
        }
        return array;
    }
}
