// 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.ClothInstance
using System;
using System.Collections.Generic;
using Eden.AutoMorpher;
using UnityEngine;

[Serializable]
public class ClothInstance
{
	public SkinnedMeshRenderer smr;

	public Mesh editableMesh;

	public Mesh bakedMesh;

	public Matrix4x4 worldNoScale;

	public Vector3[] worldVertices;

	public Vector3[] minDistanceVector;

	public float[] minDistance;

	public Vector3[] deltas;

	public Vector3[] deltasLocal;

	public List<int>[] vertexAdjacency;

	public List<List<int>> equivalentVertices;

	public bool[] isInsideVertex;

	public bool[] excludedVertices;

	public bool[] isLeftLegVertex;

	public bool[] isRightLegVertex;

	public Vector3[] bakedWorldNormals;

	public Vector4[] bakedWorldTangents;

	public Dictionary<HumanBodyBones, HashSet<Transform>> humanoidMatchedBones;

	public ClothInstance(SkinnedMeshRenderer clotheSMR, bool duplicateMesh = true)
	{
		smr = clotheSMR;
		if (duplicateMesh)
		{
			string name = smr.sharedMesh.name;
			editableMesh = UnityEngine.Object.Instantiate(clotheSMR.sharedMesh);
			editableMesh.name = name + "_EditableMesh";
			smr.sharedMesh = editableMesh;
		}
		else
		{
			editableMesh = smr.sharedMesh;
		}
		UpdateWorldVertices();
		int vertexCount = editableMesh.vertexCount;
		minDistanceVector = new Vector3[vertexCount];
		deltas = new Vector3[vertexCount];
		minDistance = new float[vertexCount];
		isInsideVertex = new bool[vertexCount];
		excludedVertices = new bool[vertexCount];
		isLeftLegVertex = new bool[vertexCount];
		isRightLegVertex = new bool[vertexCount];
		humanoidMatchedBones = new Dictionary<HumanBodyBones, HashSet<Transform>>();
		vertexAdjacency = BuildVertexAdjacency(editableMesh);
		BuildEquivalentVerticesFromWorld();
	}

	public void UpdateWorldVertices()
	{
		if (bakedMesh == null)
		{
			bakedMesh = new Mesh();
		}
		else
		{
			bakedMesh.Clear();
		}
		smr.BakeMesh(bakedMesh);
		int vertexCount = editableMesh.vertexCount;
		Vector3 lossyScale = smr.transform.lossyScale;
		Vector3 vector = new Vector3(1f / Mathf.Max(lossyScale.x, 1E-08f), 1f / Mathf.Max(lossyScale.y, 1E-08f), 1f / Mathf.Max(lossyScale.z, 1E-08f));
		worldNoScale = smr.transform.localToWorldMatrix * Matrix4x4.Scale(vector);
		worldVertices = new Vector3[vertexCount];
		deltasLocal = new Vector3[vertexCount];
		for (int i = 0; i < vertexCount; i++)
		{
			worldVertices[i] = worldNoScale.MultiplyPoint3x4(bakedMesh.vertices[i]);
			deltasLocal[i] = Vector3.zero;
		}
		Vector3[] normals = bakedMesh.normals;
		Vector4[] tangents = bakedMesh.tangents;
		bakedWorldNormals = new Vector3[vertexCount];
		if (tangents != null && tangents.Length == vertexCount)
		{
			bakedWorldTangents = new Vector4[vertexCount];
		}
		else
		{
			bakedWorldTangents = null;
		}
		for (int j = 0; j < vertexCount; j++)
		{
			bakedWorldNormals[j] = smr.transform.TransformDirection(normals[j]).normalized;
			if (bakedWorldTangents != null)
			{
				Vector3 normalized = smr.transform.TransformDirection(new Vector3(tangents[j].x, tangents[j].y, tangents[j].z)).normalized;
				bakedWorldTangents[j] = new Vector4(normalized.x, normalized.y, normalized.z, tangents[j].w);
			}
		}
	}

	public List<int>[] BuildVertexAdjacency(Mesh mesh, float seamThreshold = 0.0001f, float proximityThreshold = 0f)
	{
		if (mesh == null)
		{
			throw new AutoMorpherException("Mesh is Missing", "[VertexAdjacencyUtil] BuildVertexAdjacency\n - mesh is null");
		}
		int vertexCount = mesh.vertexCount;
		int[] triangles = mesh.triangles;
		Vector3[] vertices = mesh.vertices;
		List<int>[] array = new List<int>[vertexCount];
		for (int i = 0; i < vertexCount; i++)
		{
			array[i] = new List<int>();
		}
		int num = triangles.Length / 3;
		for (int j = 0; j < num; j++)
		{
			int num2 = triangles[j * 3];
			int num3 = triangles[j * 3 + 1];
			int num4 = triangles[j * 3 + 2];
			AddNeighbor(array, num2, num3);
			AddNeighbor(array, num3, num2);
			AddNeighbor(array, num3, num4);
			AddNeighbor(array, num4, num3);
			AddNeighbor(array, num4, num2);
			AddNeighbor(array, num2, num4);
		}
		if (seamThreshold > 0f)
		{
			float num5 = seamThreshold * 2f;
			float num6 = seamThreshold * seamThreshold;
			Dictionary<Vector3Int, List<int>> dictionary = new Dictionary<Vector3Int, List<int>>();
			for (int k = 0; k < vertexCount; k++)
			{
				Vector3 vector = vertices[k];
				Vector3Int key = new Vector3Int(Mathf.FloorToInt(vector.x / num5), Mathf.FloorToInt(vector.y / num5), Mathf.FloorToInt(vector.z / num5));
				if (!dictionary.TryGetValue(key, out var value))
				{
					value = (dictionary[key] = new List<int>());
				}
				value.Add(k);
			}
			foreach (KeyValuePair<Vector3Int, List<int>> item in dictionary)
			{
				Vector3Int key2 = item.Key;
				List<int> value2 = item.Value;
				for (int l = -1; l <= 1; l++)
				{
					for (int m = -1; m <= 1; m++)
					{
						for (int n = -1; n <= 1; n++)
						{
							if (l < 0 || (l == 0 && m < 0) || (l == 0 && m == 0 && n < 0))
							{
								continue;
							}
							Vector3Int vector3Int = new Vector3Int(key2.x + l, key2.y + m, key2.z + n);
							if (!dictionary.TryGetValue(vector3Int, out var value3))
							{
								continue;
							}
							if (vector3Int == key2)
							{
								for (int num7 = 0; num7 < value2.Count; num7++)
								{
									int num8 = value2[num7];
									Vector3 vector2 = vertices[num8];
									for (int num9 = num7 + 1; num9 < value2.Count; num9++)
									{
										int num10 = value2[num9];
										if ((vertices[num10] - vector2).sqrMagnitude <= num6)
										{
											AddNeighbor(array, num8, num10);
											AddNeighbor(array, num10, num8);
										}
									}
								}
								continue;
							}
							for (int num11 = 0; num11 < value2.Count; num11++)
							{
								int num12 = value2[num11];
								Vector3 vector3 = vertices[num12];
								for (int num13 = 0; num13 < value3.Count; num13++)
								{
									int num14 = value3[num13];
									if ((vertices[num14] - vector3).sqrMagnitude <= num6)
									{
										AddNeighbor(array, num12, num14);
										AddNeighbor(array, num14, num12);
									}
								}
							}
						}
					}
				}
			}
		}
		if (proximityThreshold > 0f)
		{
			float num15 = proximityThreshold * 2f;
			float num16 = proximityThreshold * proximityThreshold;
			Dictionary<Vector3Int, List<int>> dictionary2 = new Dictionary<Vector3Int, List<int>>();
			for (int num17 = 0; num17 < vertexCount; num17++)
			{
				Vector3 vector4 = vertices[num17];
				Vector3Int key3 = new Vector3Int(Mathf.FloorToInt(vector4.x / num15), Mathf.FloorToInt(vector4.y / num15), Mathf.FloorToInt(vector4.z / num15));
				if (!dictionary2.TryGetValue(key3, out var value4))
				{
					value4 = (dictionary2[key3] = new List<int>());
				}
				value4.Add(num17);
			}
			foreach (KeyValuePair<Vector3Int, List<int>> item2 in dictionary2)
			{
				Vector3Int key4 = item2.Key;
				List<int> value5 = item2.Value;
				for (int num18 = -1; num18 <= 1; num18++)
				{
					for (int num19 = -1; num19 <= 1; num19++)
					{
						for (int num20 = -1; num20 <= 1; num20++)
						{
							if (num18 < 0 || (num18 == 0 && num19 < 0) || (num18 == 0 && num19 == 0 && num20 < 0))
							{
								continue;
							}
							Vector3Int vector3Int2 = new Vector3Int(key4.x + num18, key4.y + num19, key4.z + num20);
							if (!dictionary2.TryGetValue(vector3Int2, out var value6))
							{
								continue;
							}
							if (vector3Int2 == key4)
							{
								for (int num21 = 0; num21 < value5.Count; num21++)
								{
									int num22 = value5[num21];
									Vector3 vector5 = vertices[num22];
									for (int num23 = num21 + 1; num23 < value5.Count; num23++)
									{
										int num24 = value5[num23];
										if ((vertices[num24] - vector5).sqrMagnitude <= num16)
										{
											AddNeighbor(array, num22, num24);
											AddNeighbor(array, num24, num22);
										}
									}
								}
								continue;
							}
							for (int num25 = 0; num25 < value5.Count; num25++)
							{
								int num26 = value5[num25];
								Vector3 vector6 = vertices[num26];
								for (int num27 = 0; num27 < value6.Count; num27++)
								{
									int num28 = value6[num27];
									if ((vertices[num28] - vector6).sqrMagnitude <= num16)
									{
										AddNeighbor(array, num26, num28);
										AddNeighbor(array, num28, num26);
									}
								}
							}
						}
					}
				}
			}
		}
		return array;
		static void AddNeighbor(List<int>[] adj, int from, int to)
		{
			List<int> list3 = adj[from];
			if (!list3.Contains(to))
			{
				list3.Add(to);
			}
		}
	}

	public void ApplyWorldVerticesToMesh()
	{
		if (editableMesh == null || smr == null || worldVertices == null)
		{
			return;
		}
		Mesh mesh = editableMesh;
		int vertexCount = mesh.vertexCount;
		Vector3[] vertices = mesh.vertices;
		SkinningUtil skinningUtil = new SkinningUtil();
		Vector3[] array = null;
		int blendShapeCount = mesh.blendShapeCount;
		if (blendShapeCount > 0)
		{
			array = new Vector3[vertexCount];
			Vector3[] array2 = new Vector3[vertexCount];
			Vector3[] deltaNormals = new Vector3[vertexCount];
			Vector3[] deltaTangents = new Vector3[vertexCount];
			for (int i = 0; i < blendShapeCount; i++)
			{
				float blendShapeWeight = smr.GetBlendShapeWeight(i);
				if (Mathf.Approximately(blendShapeWeight, 0f))
				{
					continue;
				}
				int frameIndex = mesh.GetBlendShapeFrameCount(i) - 1;
				float blendShapeFrameWeight = mesh.GetBlendShapeFrameWeight(i, frameIndex);
				mesh.GetBlendShapeFrameVertices(i, frameIndex, array2, deltaNormals, deltaTangents);
				float num = ((blendShapeFrameWeight != 0f) ? (blendShapeWeight / blendShapeFrameWeight) : 0f);
				if (!Mathf.Approximately(num, 0f))
				{
					for (int j = 0; j < vertexCount; j++)
					{
						array[j] += array2[j] * num;
					}
				}
			}
		}
		for (int k = 0; k < vertexCount; k++)
		{
			Vector3 vector = skinningUtil.WorldPosToBindPos_Full(smr, mesh, k, worldVertices[k]);
			if (array != null)
			{
				vector -= array[k];
			}
			vertices[k] = vector;
		}
		mesh.vertices = vertices;
		Vector3[] array3 = null;
		Vector3[] array4 = null;
		if (blendShapeCount > 0)
		{
			array3 = new Vector3[vertexCount];
			array4 = new Vector3[vertexCount];
			Vector3[] deltaVertices = new Vector3[vertexCount];
			Vector3[] array5 = new Vector3[vertexCount];
			Vector3[] array6 = new Vector3[vertexCount];
			for (int l = 0; l < blendShapeCount; l++)
			{
				float blendShapeWeight2 = smr.GetBlendShapeWeight(l);
				if (Mathf.Approximately(blendShapeWeight2, 0f))
				{
					continue;
				}
				int frameIndex2 = mesh.GetBlendShapeFrameCount(l) - 1;
				float blendShapeFrameWeight2 = mesh.GetBlendShapeFrameWeight(l, frameIndex2);
				mesh.GetBlendShapeFrameVertices(l, frameIndex2, deltaVertices, array5, array6);
				float num2 = ((blendShapeFrameWeight2 != 0f) ? (blendShapeWeight2 / blendShapeFrameWeight2) : 0f);
				if (!Mathf.Approximately(num2, 0f))
				{
					for (int m = 0; m < vertexCount; m++)
					{
						array3[m] += array5[m] * num2;
						array4[m] += array6[m] * num2;
					}
				}
			}
		}
		if (bakedWorldNormals == null || bakedWorldNormals.Length != vertexCount)
		{
			return;
		}
		Vector3[] array7 = new Vector3[vertexCount];
		bool flag = bakedWorldTangents != null && bakedWorldTangents.Length == vertexCount;
		Vector4[] array8 = (flag ? new Vector4[vertexCount] : null);
		for (int n = 0; n < vertexCount; n++)
		{
			Vector3 vector2 = skinningUtil.WorldDirToBindDir_Full(smr, mesh, n, bakedWorldNormals[n]);
			if (array3 != null)
			{
				vector2 -= array3[n];
			}
			array7[n] = vector2.normalized;
			if (flag)
			{
				Vector3 vector3 = skinningUtil.WorldDirToBindDir_Full(targetWorldDir: new Vector3(bakedWorldTangents[n].x, bakedWorldTangents[n].y, bakedWorldTangents[n].z), smr: smr, bindMesh: mesh, vertexIndex: n);
				if (array4 != null)
				{
					vector3 -= array4[n];
				}
				vector3 = vector3.normalized;
				array8[n] = new Vector4(vector3.x, vector3.y, vector3.z, bakedWorldTangents[n].w);
			}
		}
		mesh.normals = array7;
		if (array8 != null)
		{
			mesh.tangents = array8;
		}
	}

	public void BuildEquivalentVerticesFromWorld(float maxDistance = 1E-05f)
	{
		if (worldVertices == null || worldVertices.Length == 0)
		{
			Debug.LogWarning("[ClothInstance] BuildEquivalentVerticesFromWorld: worldVertices is null or empty. Call UpdateWorldVertices() first.");
			return;
		}
		int num = worldVertices.Length;
		if (equivalentVertices == null)
		{
			equivalentVertices = new List<List<int>>();
		}
		else
		{
			equivalentVertices.Clear();
		}
		float num2 = maxDistance * maxDistance;
		Dictionary<Vector3Int, List<int>> dictionary = new Dictionary<Vector3Int, List<int>>();
		for (int i = 0; i < num; i++)
		{
			Vector3 vector = worldVertices[i];
			Vector3Int key = new Vector3Int(Mathf.FloorToInt(vector.x / maxDistance), Mathf.FloorToInt(vector.y / maxDistance), Mathf.FloorToInt(vector.z / maxDistance));
			if (!dictionary.TryGetValue(key, out var value))
			{
				value = (dictionary[key] = new List<int>());
			}
			value.Add(i);
		}
		foreach (KeyValuePair<Vector3Int, List<int>> item in dictionary)
		{
			List<int> value2 = item.Value;
			int count = value2.Count;
			if (count < 2)
			{
				continue;
			}
			int[] parent = new int[count];
			for (int j = 0; j < count; j++)
			{
				parent[j] = j;
			}
			for (int k = 0; k < count; k++)
			{
				int num3 = value2[k];
				Vector3 vector2 = worldVertices[num3];
				for (int l = k + 1; l < count; l++)
				{
					int num4 = value2[l];
					Vector3 vector3 = worldVertices[num4];
					if ((vector2 - vector3).sqrMagnitude <= num2)
					{
						Union(k, l);
					}
				}
			}
			Dictionary<int, List<int>> dictionary2 = new Dictionary<int, List<int>>();
			for (int m = 0; m < count; m++)
			{
				int key2 = Find(m);
				if (!dictionary2.TryGetValue(key2, out var value3))
				{
					value3 = (dictionary2[key2] = new List<int>());
				}
				value3.Add(value2[m]);
			}
			foreach (List<int> value4 in dictionary2.Values)
			{
				if (value4.Count >= 2)
				{
					equivalentVertices.Add(value4);
				}
			}
			int Find(int x)
			{
				if (parent[x] != x)
				{
					parent[x] = Find(parent[x]);
				}
				return parent[x];
			}
			void Union(int a, int b)
			{
				int num5 = Find(a);
				int num6 = Find(b);
				if (num5 != num6)
				{
					parent[num6] = num5;
				}
			}
		}
	}

	~ClothInstance()
	{
		Dispose();
	}

	public void Dispose()
	{
		if (bakedMesh != null)
		{
			UnityEngine.Object.DestroyImmediate(bakedMesh);
			bakedMesh = null;
		}
		worldVertices = null;
		minDistanceVector = null;
		minDistance = null;
		deltas = null;
		deltasLocal = null;
		isInsideVertex = null;
		excludedVertices = null;
		isLeftLegVertex = null;
		isRightLegVertex = null;
		vertexAdjacency = null;
		if (equivalentVertices != null)
		{
			for (int i = 0; i < equivalentVertices.Count; i++)
			{
				equivalentVertices[i]?.Clear();
			}
			equivalentVertices.Clear();
			equivalentVertices = null;
		}
		humanoidMatchedBones = null;
		smr = null;
		editableMesh = null;
	}
}
