Decompiled source of BetterSphere v1.0.0

BetterSphere.dll

Decompiled 9 hours ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using NGPT;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;
using UnityMeshSimplifier;
using UnityMeshSimplifier.Internal;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Better Sphere")]
[assembly: AssemblyCompany("Loki Moon Labs")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("Whinarn.UnityMeshSimplifier.Editor")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace UnityMeshSimplifier
{
	[Serializable]
	[StructLayout(LayoutKind.Auto)]
	public struct BlendShape
	{
		public string ShapeName;

		public BlendShapeFrame[] Frames;

		public BlendShape(string shapeName, BlendShapeFrame[] frames)
		{
			ShapeName = shapeName;
			Frames = frames;
		}
	}
	[Serializable]
	[StructLayout(LayoutKind.Auto)]
	public struct BlendShapeFrame
	{
		public float FrameWeight;

		public Vector3[] DeltaVertices;

		public Vector3[] DeltaNormals;

		public Vector3[] DeltaTangents;

		public BlendShapeFrame(float frameWeight, Vector3[] deltaVertices, Vector3[] deltaNormals, Vector3[] deltaTangents)
		{
			FrameWeight = frameWeight;
			DeltaVertices = deltaVertices;
			DeltaNormals = deltaNormals;
			DeltaTangents = deltaTangents;
		}
	}
	public static class LODGenerator
	{
		private struct RendererInfo
		{
			public string name;

			public bool isStatic;

			public bool isNewMesh;

			public Transform transform;

			public Mesh mesh;

			public Material[] materials;

			public Transform rootBone;

			public Transform[] bones;
		}

		public static readonly string LODParentGameObjectName = "_UMS_LODs_";

		public static readonly string LODAssetDefaultParentPath = "Assets/UMS_LODs/";

		public static readonly string AssetsRootPath = "Assets/";

		public static readonly string LODAssetUserData = "UnityMeshSimplifierLODAsset";

		public static LODGroup GenerateLODs(LODGeneratorHelper generatorHelper)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)generatorHelper == (Object)null)
			{
				throw new ArgumentNullException("generatorHelper");
			}
			GameObject gameObject = ((Component)generatorHelper).gameObject;
			LODLevel[] levels = generatorHelper.Levels;
			bool autoCollectRenderers = generatorHelper.AutoCollectRenderers;
			SimplificationOptions simplificationOptions = generatorHelper.SimplificationOptions;
			string saveAssetsPath = generatorHelper.SaveAssetsPath;
			LODGroup val = GenerateLODs(gameObject, levels, autoCollectRenderers, simplificationOptions, saveAssetsPath);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			val.animateCrossFading = generatorHelper.AnimateCrossFading;
			val.fadeMode = generatorHelper.FadeMode;
			return val;
		}

		public static LODGroup GenerateLODs(GameObject gameObject, LODLevel[] levels, bool autoCollectRenderers, SimplificationOptions simplificationOptions)
		{
			return GenerateLODs(gameObject, levels, autoCollectRenderers, simplificationOptions, null);
		}

		public static LODGroup GenerateLODs(GameObject gameObject, LODLevel[] levels, bool autoCollectRenderers, SimplificationOptions simplificationOptions, string saveAssetsPath)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)gameObject == (Object)null)
			{
				throw new ArgumentNullException("gameObject");
			}
			if (levels == null)
			{
				throw new ArgumentNullException("levels");
			}
			Transform transform = gameObject.transform;
			if ((Object)(object)transform.Find(LODParentGameObjectName) != (Object)null)
			{
				throw new InvalidOperationException("The game object already appears to have LODs. Please remove them first.");
			}
			if ((Object)(object)gameObject.GetComponent<LODGroup>() != (Object)null)
			{
				throw new InvalidOperationException("The game object already appears to have a LOD Group. Please remove it first.");
			}
			MeshSimplifier.ValidateOptions(simplificationOptions);
			saveAssetsPath = ValidateSaveAssetsPath(saveAssetsPath);
			Transform transform2 = new GameObject(LODParentGameObjectName).transform;
			ParentAndResetTransform(transform2, transform);
			LODGroup val = gameObject.AddComponent<LODGroup>();
			Renderer[] array = null;
			if (autoCollectRenderers)
			{
				array = GetChildRenderersForLOD(gameObject);
			}
			List<Renderer> list = new List<Renderer>((array != null) ? array.Length : 10);
			LOD[] array2 = (LOD[])(object)new LOD[levels.Length];
			for (int i = 0; i < levels.Length; i++)
			{
				LODLevel level = levels[i];
				Transform transform3 = new GameObject($"Level{i:00}").transform;
				ParentAndResetTransform(transform3, transform2);
				Renderer[] array3 = array ?? level.Renderers;
				List<Renderer> list2 = new List<Renderer>((array3 != null) ? array3.Length : 0);
				if (array3 != null && array3.Length != 0)
				{
					MeshRenderer[] renderers = (from val2 in array3
						let meshFilter = ((Component)val2).GetComponent<MeshFilter>()
						let renderer = val2
						where renderer.enabled && (Object)/*isinst with value type is only supported in some contexts*/ != (Object)null && (Object)(object)meshFilter != (Object)null && (Object)(object)meshFilter.sharedMesh != (Object)null
						select <>h__TransparentIdentifier0).Select(<>h__TransparentIdentifier0 =>
					{
						Renderer renderer3 = <>h__TransparentIdentifier0.renderer;
						return (MeshRenderer)(object)((renderer3 is MeshRenderer) ? renderer3 : null);
					}).ToArray();
					SkinnedMeshRenderer[] renderers2 = (from val2 in array3
						where val2.enabled && (Object)(object)((val2 is SkinnedMeshRenderer) ? val2 : null) != (Object)null && (Object)(object)((SkinnedMeshRenderer)((val2 is SkinnedMeshRenderer) ? val2 : null)).sharedMesh != (Object)null
						select (SkinnedMeshRenderer)(object)((val2 is SkinnedMeshRenderer) ? val2 : null)).ToArray();
					RendererInfo[] array4;
					RendererInfo[] array5;
					if (level.CombineMeshes)
					{
						array4 = CombineStaticMeshes(transform, i, renderers);
						array5 = CombineSkinnedMeshes(transform, i, renderers2);
					}
					else
					{
						array4 = GetStaticRenderers(renderers);
						array5 = GetSkinnedRenderers(renderers2);
					}
					if (array4 != null)
					{
						for (int num = 0; num < array4.Length; num++)
						{
							RendererInfo renderer = array4[num];
							Renderer item = CreateLevelRenderer(gameObject, i, in level, transform3, num, in renderer, in simplificationOptions, saveAssetsPath);
							list2.Add(item);
						}
					}
					if (array5 != null)
					{
						for (int num2 = 0; num2 < array5.Length; num2++)
						{
							RendererInfo renderer2 = array5[num2];
							Renderer item2 = CreateLevelRenderer(gameObject, i, in level, transform3, num2, in renderer2, in simplificationOptions, saveAssetsPath);
							list2.Add(item2);
						}
					}
					Renderer[] array6 = array3;
					foreach (Renderer item3 in array6)
					{
						if (!list.Contains(item3))
						{
							list.Add(item3);
						}
					}
				}
				array2[i] = new LOD(level.ScreenRelativeTransitionHeight, list2.ToArray());
			}
			CreateBackup(gameObject, list.ToArray());
			foreach (Renderer item4 in list)
			{
				item4.enabled = false;
			}
			val.animateCrossFading = false;
			val.SetLODs(array2);
			return val;
		}

		public static bool DestroyLODs(LODGeneratorHelper generatorHelper)
		{
			if ((Object)(object)generatorHelper == (Object)null)
			{
				throw new ArgumentNullException("generatorHelper");
			}
			return DestroyLODs(((Component)generatorHelper).gameObject);
		}

		public static bool DestroyLODs(GameObject gameObject)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				throw new ArgumentNullException("gameObject");
			}
			RestoreBackup(gameObject);
			Transform val = gameObject.transform.Find(LODParentGameObjectName);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			DestroyObject((Object)(object)((Component)val).gameObject);
			LODGroup component = gameObject.GetComponent<LODGroup>();
			if ((Object)(object)component != (Object)null)
			{
				DestroyObject((Object)(object)component);
			}
			return true;
		}

		private static RendererInfo[] GetStaticRenderers(MeshRenderer[] renderers)
		{
			List<RendererInfo> list = new List<RendererInfo>(renderers.Length);
			foreach (MeshRenderer val in renderers)
			{
				MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
				if ((Object)(object)component == (Object)null)
				{
					Debug.LogWarning((object)"A renderer was missing a mesh filter and was ignored.", (Object)(object)val);
					continue;
				}
				Mesh sharedMesh = component.sharedMesh;
				if ((Object)(object)sharedMesh == (Object)null)
				{
					Debug.LogWarning((object)"A renderer was missing a mesh and was ignored.", (Object)(object)val);
					continue;
				}
				list.Add(new RendererInfo
				{
					name = ((Object)val).name,
					isStatic = true,
					isNewMesh = false,
					transform = ((Component)val).transform,
					mesh = sharedMesh,
					materials = ((Renderer)val).sharedMaterials
				});
			}
			return list.ToArray();
		}

		private static RendererInfo[] GetSkinnedRenderers(SkinnedMeshRenderer[] renderers)
		{
			List<RendererInfo> list = new List<RendererInfo>(renderers.Length);
			foreach (SkinnedMeshRenderer val in renderers)
			{
				Mesh sharedMesh = val.sharedMesh;
				if ((Object)(object)sharedMesh == (Object)null)
				{
					Debug.LogWarning((object)"A renderer was missing a mesh and was ignored.", (Object)(object)val);
					continue;
				}
				list.Add(new RendererInfo
				{
					name = ((Object)val).name,
					isStatic = false,
					isNewMesh = false,
					transform = ((Component)val).transform,
					mesh = sharedMesh,
					materials = ((Renderer)val).sharedMaterials,
					rootBone = val.rootBone,
					bones = val.bones
				});
			}
			return list.ToArray();
		}

		private static RendererInfo[] CombineStaticMeshes(Transform transform, int levelIndex, MeshRenderer[] renderers)
		{
			if (renderers.Length == 0)
			{
				return null;
			}
			List<RendererInfo> list = new List<RendererInfo>(renderers.Length);
			Material[] resultMaterials;
			Mesh val = MeshCombiner.CombineMeshes(transform, renderers, out resultMaterials);
			((Object)val).name = $"{((Object)transform).name}_static{levelIndex:00}";
			string name = $"{((Object)transform).name}_combined_static";
			list.Add(new RendererInfo
			{
				name = name,
				isStatic = true,
				isNewMesh = true,
				transform = null,
				mesh = val,
				materials = resultMaterials,
				rootBone = null,
				bones = null
			});
			return list.ToArray();
		}

		private static RendererInfo[] CombineSkinnedMeshes(Transform transform, int levelIndex, SkinnedMeshRenderer[] renderers)
		{
			if (renderers.Length == 0)
			{
				return null;
			}
			List<RendererInfo> list = new List<RendererInfo>(renderers.Length);
			IEnumerable<SkinnedMeshRenderer> enumerable = renderers.Where((SkinnedMeshRenderer renderer) => (Object)(object)renderer.sharedMesh != (Object)null && renderer.sharedMesh.blendShapeCount > 0);
			IEnumerable<SkinnedMeshRenderer> enumerable2 = renderers.Where((SkinnedMeshRenderer renderer) => (Object)(object)renderer.sharedMesh == (Object)null);
			SkinnedMeshRenderer[] array = renderers.Where((SkinnedMeshRenderer renderer) => (Object)(object)renderer.sharedMesh != (Object)null && renderer.sharedMesh.blendShapeCount == 0).ToArray();
			foreach (SkinnedMeshRenderer item in enumerable2)
			{
				Debug.LogWarning((object)"A renderer was missing a mesh and was ignored.", (Object)(object)item);
			}
			foreach (SkinnedMeshRenderer item2 in enumerable)
			{
				list.Add(new RendererInfo
				{
					name = ((Object)item2).name,
					isStatic = false,
					isNewMesh = false,
					transform = ((Component)item2).transform,
					mesh = item2.sharedMesh,
					materials = ((Renderer)item2).sharedMaterials,
					rootBone = item2.rootBone,
					bones = item2.bones
				});
			}
			if (array.Length != 0)
			{
				Material[] resultMaterials;
				Transform[] resultBones;
				Mesh val = MeshCombiner.CombineMeshes(transform, array, out resultMaterials, out resultBones);
				((Object)val).name = $"{((Object)transform).name}_skinned{levelIndex:00}";
				Transform rootBone = FindBestRootBone(transform, array);
				string name = $"{((Object)transform).name}_combined_skinned";
				list.Add(new RendererInfo
				{
					name = name,
					isStatic = false,
					isNewMesh = false,
					transform = null,
					mesh = val,
					materials = resultMaterials,
					rootBone = rootBone,
					bones = resultBones
				});
			}
			return list.ToArray();
		}

		private static void ParentAndResetTransform(Transform transform, Transform parentTransform)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			transform.SetParent(parentTransform);
			transform.localPosition = Vector3.zero;
			transform.localRotation = Quaternion.identity;
			transform.localScale = Vector3.one;
		}

		private static void ParentAndOffsetTransform(Transform transform, Transform parentTransform, Transform originalTransform)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			transform.position = originalTransform.position;
			transform.rotation = originalTransform.rotation;
			transform.localScale = originalTransform.lossyScale;
			transform.SetParent(parentTransform, true);
		}

		private static Renderer CreateLevelRenderer(GameObject gameObject, int levelIndex, in LODLevel level, Transform levelTransform, int rendererIndex, in RendererInfo renderer, in SimplificationOptions simplificationOptions, string saveAssetsPath)
		{
			Mesh mesh = renderer.mesh;
			if (level.Quality < 1f)
			{
				mesh = SimplifyMesh(mesh, level.Quality, in simplificationOptions);
				if (renderer.isNewMesh)
				{
					DestroyObject((Object)(object)renderer.mesh);
				}
			}
			if (renderer.isStatic)
			{
				return (Renderer)(object)CreateStaticLevelRenderer($"{rendererIndex:000}_static_{renderer.name}", levelTransform, renderer.transform, mesh, renderer.materials, in level);
			}
			return (Renderer)(object)CreateSkinnedLevelRenderer($"{rendererIndex:000}_skinned_{renderer.name}", levelTransform, renderer.transform, mesh, renderer.materials, renderer.rootBone, renderer.bones, in level);
		}

		private static MeshRenderer CreateStaticLevelRenderer(string name, Transform parentTransform, Transform originalTransform, Mesh mesh, Material[] materials, in LODLevel level)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(MeshFilter),
				typeof(MeshRenderer)
			});
			Transform transform = val.transform;
			if ((Object)(object)originalTransform != (Object)null)
			{
				ParentAndOffsetTransform(transform, parentTransform, originalTransform);
			}
			else
			{
				ParentAndResetTransform(transform, parentTransform);
			}
			val.GetComponent<MeshFilter>().sharedMesh = mesh;
			MeshRenderer component = val.GetComponent<MeshRenderer>();
			((Renderer)component).sharedMaterials = materials;
			SetupLevelRenderer((Renderer)(object)component, in level);
			return component;
		}

		private static SkinnedMeshRenderer CreateSkinnedLevelRenderer(string name, Transform parentTransform, Transform originalTransform, Mesh mesh, Material[] materials, Transform rootBone, Transform[] bones, in LODLevel level)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(SkinnedMeshRenderer) });
			Transform transform = val.transform;
			if ((Object)(object)originalTransform != (Object)null)
			{
				ParentAndOffsetTransform(transform, parentTransform, originalTransform);
			}
			else
			{
				ParentAndResetTransform(transform, parentTransform);
			}
			SkinnedMeshRenderer component = val.GetComponent<SkinnedMeshRenderer>();
			component.sharedMesh = mesh;
			((Renderer)component).sharedMaterials = materials;
			component.rootBone = rootBone;
			component.bones = bones;
			SetupLevelRenderer((Renderer)(object)component, in level);
			return component;
		}

		private static Transform FindBestRootBone(Transform transform, SkinnedMeshRenderer[] skinnedMeshRenderers)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (skinnedMeshRenderers == null || skinnedMeshRenderers.Length == 0)
			{
				return null;
			}
			Transform result = null;
			float num = float.MaxValue;
			for (int i = 0; i < skinnedMeshRenderers.Length; i++)
			{
				if (!((Object)(object)skinnedMeshRenderers[i] == (Object)null) && !((Object)(object)skinnedMeshRenderers[i].rootBone == (Object)null))
				{
					Transform rootBone = skinnedMeshRenderers[i].rootBone;
					Vector3 val = rootBone.position - transform.position;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						result = rootBone;
						num = sqrMagnitude;
					}
				}
			}
			return result;
		}

		private static void SetupLevelRenderer(Renderer renderer, in LODLevel level)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			renderer.shadowCastingMode = level.ShadowCastingMode;
			renderer.receiveShadows = level.ReceiveShadows;
			renderer.motionVectorGenerationMode = level.MotionVectorGenerationMode;
			renderer.lightProbeUsage = level.LightProbeUsage;
			renderer.reflectionProbeUsage = level.ReflectionProbeUsage;
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
			if ((Object)(object)val != (Object)null)
			{
				val.quality = level.SkinQuality;
				val.skinnedMotionVectors = level.SkinnedMotionVectors;
			}
		}

		private static Renderer[] GetChildRenderersForLOD(GameObject gameObject)
		{
			List<Renderer> list = new List<Renderer>();
			CollectChildRenderersForLOD(gameObject.transform, list);
			return list.ToArray();
		}

		private static void CollectChildRenderersForLOD(Transform transform, List<Renderer> resultRenderers)
		{
			Renderer[] components = ((Component)transform).GetComponents<Renderer>();
			resultRenderers.AddRange(components);
			int childCount = transform.childCount;
			for (int i = 0; i < childCount; i++)
			{
				Transform child = transform.GetChild(i);
				if (((Component)child).gameObject.activeSelf && !string.Equals(((Object)child).name, LODParentGameObjectName) && !((Object)(object)((Component)child).GetComponent<LODGroup>() != (Object)null) && !((Object)(object)((Component)child).GetComponent<LODGeneratorHelper>() != (Object)null))
				{
					CollectChildRenderersForLOD(child, resultRenderers);
				}
			}
		}

		private static Mesh SimplifyMesh(Mesh mesh, float quality, in SimplificationOptions options)
		{
			MeshSimplifier meshSimplifier = new MeshSimplifier();
			meshSimplifier.SimplificationOptions = options;
			meshSimplifier.Initialize(mesh);
			meshSimplifier.SimplifyMesh(quality);
			Mesh obj = meshSimplifier.ToMesh();
			obj.bindposes = mesh.bindposes;
			return obj;
		}

		private static void DestroyObject(Object obj)
		{
			if (obj == (Object)null)
			{
				throw new ArgumentNullException("obj");
			}
			Object.Destroy(obj);
		}

		private static void CreateBackup(GameObject gameObject, Renderer[] originalRenderers)
		{
			LODBackupComponent lODBackupComponent = gameObject.AddComponent<LODBackupComponent>();
			((Object)lODBackupComponent).hideFlags = (HideFlags)2;
			lODBackupComponent.OriginalRenderers = originalRenderers;
		}

		private static void RestoreBackup(GameObject gameObject)
		{
			LODBackupComponent[] components = gameObject.GetComponents<LODBackupComponent>();
			foreach (LODBackupComponent lODBackupComponent in components)
			{
				Renderer[] originalRenderers = lODBackupComponent.OriginalRenderers;
				if (originalRenderers != null)
				{
					Renderer[] array = originalRenderers;
					foreach (Renderer val in array)
					{
						if ((Object)(object)val != (Object)null)
						{
							val.enabled = true;
						}
					}
				}
				DestroyObject((Object)(object)lODBackupComponent);
			}
		}

		private static string ValidateSaveAssetsPath(string saveAssetsPath)
		{
			if (string.IsNullOrEmpty(saveAssetsPath))
			{
				return null;
			}
			Debug.LogWarning((object)"Unable to save assets when not running in the Unity Editor.");
			return null;
		}
	}
	[Serializable]
	public struct LODLevel
	{
		[SerializeField]
		[Range(0f, 1f)]
		[Tooltip("The screen relative height to use for the transition.")]
		private float screenRelativeTransitionHeight;

		[SerializeField]
		[Range(0f, 1f)]
		[Tooltip("The width of the cross-fade transition zone (proportion to the current LOD's whole length).")]
		private float fadeTransitionWidth;

		[SerializeField]
		[Range(0f, 1f)]
		[Tooltip("The desired quality for this level.")]
		private float quality;

		[SerializeField]
		[Tooltip("If all renderers and meshes under this level should be combined into one, where possible.")]
		private bool combineMeshes;

		[SerializeField]
		[Tooltip("If all sub-meshes should be combined into one, where possible.")]
		private bool combineSubMeshes;

		[SerializeField]
		[Tooltip("The renderers used in this level.")]
		private Renderer[] renderers;

		[SerializeField]
		[Tooltip("The skin quality to use for renderers on this level.")]
		private SkinQuality skinQuality;

		[SerializeField]
		[Tooltip("The shadow casting mode for renderers on this level.")]
		private ShadowCastingMode shadowCastingMode;

		[SerializeField]
		[Tooltip("If renderers on this level should receive shadows.")]
		private bool receiveShadows;

		[SerializeField]
		[Tooltip("The motion vector generation mode for renderers on this level.")]
		private MotionVectorGenerationMode motionVectorGenerationMode;

		[SerializeField]
		[Tooltip("If renderers on this level should use skinned motion vectors.")]
		private bool skinnedMotionVectors;

		[SerializeField]
		[Tooltip("The light probe usage for renderers on this level.")]
		private LightProbeUsage lightProbeUsage;

		[SerializeField]
		[Tooltip("The reflection probe usage for renderers on this level.")]
		private ReflectionProbeUsage reflectionProbeUsage;

		public float ScreenRelativeTransitionHeight
		{
			get
			{
				return screenRelativeTransitionHeight;
			}
			set
			{
				screenRelativeTransitionHeight = Mathf.Clamp01(value);
			}
		}

		public float FadeTransitionWidth
		{
			get
			{
				return fadeTransitionWidth;
			}
			set
			{
				fadeTransitionWidth = Mathf.Clamp01(value);
			}
		}

		public float Quality
		{
			get
			{
				return quality;
			}
			set
			{
				quality = Mathf.Clamp01(value);
			}
		}

		public bool CombineMeshes
		{
			get
			{
				return combineMeshes;
			}
			set
			{
				combineMeshes = value;
			}
		}

		public bool CombineSubMeshes
		{
			get
			{
				return combineSubMeshes;
			}
			set
			{
				combineSubMeshes = value;
			}
		}

		public Renderer[] Renderers
		{
			get
			{
				return renderers;
			}
			set
			{
				renderers = value;
			}
		}

		public SkinQuality SkinQuality
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return skinQuality;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				skinQuality = value;
			}
		}

		public ShadowCastingMode ShadowCastingMode
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return shadowCastingMode;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				shadowCastingMode = value;
			}
		}

		public bool ReceiveShadows
		{
			get
			{
				return receiveShadows;
			}
			set
			{
				receiveShadows = value;
			}
		}

		public MotionVectorGenerationMode MotionVectorGenerationMode
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return motionVectorGenerationMode;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				motionVectorGenerationMode = value;
			}
		}

		public bool SkinnedMotionVectors
		{
			get
			{
				return skinnedMotionVectors;
			}
			set
			{
				skinnedMotionVectors = value;
			}
		}

		public LightProbeUsage LightProbeUsage
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return lightProbeUsage;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				lightProbeUsage = value;
			}
		}

		public ReflectionProbeUsage ReflectionProbeUsage
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return reflectionProbeUsage;
			}
			set
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				reflectionProbeUsage = value;
			}
		}

		public LODLevel(float screenRelativeTransitionHeight, float quality)
			: this(screenRelativeTransitionHeight, 0f, quality, combineMeshes: false, combineSubMeshes: false, null)
		{
		}

		public LODLevel(float screenRelativeTransitionHeight, float fadeTransitionWidth, float quality, bool combineMeshes, bool combineSubMeshes)
			: this(screenRelativeTransitionHeight, fadeTransitionWidth, quality, combineMeshes, combineSubMeshes, null)
		{
		}

		public LODLevel(float screenRelativeTransitionHeight, float fadeTransitionWidth, float quality, bool combineMeshes, bool combineSubMeshes, Renderer[] renderers)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			this.screenRelativeTransitionHeight = Mathf.Clamp01(screenRelativeTransitionHeight);
			this.fadeTransitionWidth = fadeTransitionWidth;
			this.quality = Mathf.Clamp01(quality);
			this.combineMeshes = combineMeshes;
			this.combineSubMeshes = combineSubMeshes;
			this.renderers = renderers;
			skinQuality = (SkinQuality)0;
			shadowCastingMode = (ShadowCastingMode)1;
			receiveShadows = true;
			motionVectorGenerationMode = (MotionVectorGenerationMode)1;
			skinnedMotionVectors = true;
			lightProbeUsage = (LightProbeUsage)1;
			reflectionProbeUsage = (ReflectionProbeUsage)1;
		}
	}
	public static class MeshCombiner
	{
		public static Mesh CombineMeshes(Transform rootTransform, MeshRenderer[] renderers, out Material[] resultMaterials)
		{
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)rootTransform == (Object)null)
			{
				throw new ArgumentNullException("rootTransform");
			}
			if (renderers == null)
			{
				throw new ArgumentNullException("renderers");
			}
			Mesh[] array = (Mesh[])(object)new Mesh[renderers.Length];
			Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[renderers.Length];
			Material[][] array3 = new Material[renderers.Length][];
			for (int i = 0; i < renderers.Length; i++)
			{
				MeshRenderer val = renderers[i];
				if ((Object)(object)val == (Object)null)
				{
					throw new ArgumentException($"The renderer at index {i} is null.", "renderers");
				}
				Transform transform = ((Component)val).transform;
				MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
				if ((Object)(object)component == (Object)null)
				{
					throw new ArgumentException($"The renderer at index {i} has no mesh filter.", "renderers");
				}
				if ((Object)(object)component.sharedMesh == (Object)null)
				{
					throw new ArgumentException($"The mesh filter for renderer at index {i} has no mesh.", "renderers");
				}
				if (!CanReadMesh(component.sharedMesh))
				{
					throw new ArgumentException($"The mesh in the mesh filter for renderer at index {i} is not readable.", "renderers");
				}
				array[i] = component.sharedMesh;
				array2[i] = rootTransform.worldToLocalMatrix * transform.localToWorldMatrix;
				array3[i] = ((Renderer)val).sharedMaterials;
			}
			return CombineMeshes(array, array2, array3, out resultMaterials);
		}

		public static Mesh CombineMeshes(Transform rootTransform, SkinnedMeshRenderer[] renderers, out Material[] resultMaterials, out Transform[] resultBones)
		{
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)rootTransform == (Object)null)
			{
				throw new ArgumentNullException("rootTransform");
			}
			if (renderers == null)
			{
				throw new ArgumentNullException("renderers");
			}
			Mesh[] array = (Mesh[])(object)new Mesh[renderers.Length];
			Matrix4x4[] array2 = (Matrix4x4[])(object)new Matrix4x4[renderers.Length];
			Material[][] array3 = new Material[renderers.Length][];
			Transform[][] array4 = new Transform[renderers.Length][];
			for (int i = 0; i < renderers.Length; i++)
			{
				SkinnedMeshRenderer val = renderers[i];
				if ((Object)(object)val == (Object)null)
				{
					throw new ArgumentException($"The renderer at index {i} is null.", "renderers");
				}
				if ((Object)(object)val.sharedMesh == (Object)null)
				{
					throw new ArgumentException($"The renderer at index {i} has no mesh.", "renderers");
				}
				if (!CanReadMesh(val.sharedMesh))
				{
					throw new ArgumentException($"The mesh in the renderer at index {i} is not readable.", "renderers");
				}
				Transform transform = ((Component)val).transform;
				array[i] = val.sharedMesh;
				array2[i] = transform.worldToLocalMatrix * transform.localToWorldMatrix;
				array3[i] = ((Renderer)val).sharedMaterials;
				array4[i] = val.bones;
			}
			return CombineMeshes(array, array2, array3, array4, out resultMaterials, out resultBones);
		}

		public static Mesh CombineMeshes(Mesh[] meshes, Matrix4x4[] transforms, Material[][] materials, out Material[] resultMaterials)
		{
			if (meshes == null)
			{
				throw new ArgumentNullException("meshes");
			}
			if (transforms == null)
			{
				throw new ArgumentNullException("transforms");
			}
			if (materials == null)
			{
				throw new ArgumentNullException("materials");
			}
			Transform[] resultBones;
			return CombineMeshes(meshes, transforms, materials, null, out resultMaterials, out resultBones);
		}

		public static Mesh CombineMeshes(Mesh[] meshes, Matrix4x4[] transforms, Material[][] materials, Transform[][] bones, out Material[] resultMaterials, out Transform[] resultBones)
		{
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_042e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			if (meshes == null)
			{
				throw new ArgumentNullException("meshes");
			}
			if (transforms == null)
			{
				throw new ArgumentNullException("transforms");
			}
			if (materials == null)
			{
				throw new ArgumentNullException("materials");
			}
			if (transforms.Length != meshes.Length)
			{
				throw new ArgumentException("The array of transforms doesn't have the same length as the array of meshes.", "transforms");
			}
			if (materials.Length != meshes.Length)
			{
				throw new ArgumentException("The array of materials doesn't have the same length as the array of meshes.", "materials");
			}
			if (bones != null && bones.Length != meshes.Length)
			{
				throw new ArgumentException("The array of bones doesn't have the same length as the array of meshes.", "bones");
			}
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < meshes.Length; i++)
			{
				Mesh val = meshes[i];
				if ((Object)(object)val == (Object)null)
				{
					throw new ArgumentException($"The mesh at index {i} is null.", "meshes");
				}
				if (!CanReadMesh(val))
				{
					throw new ArgumentException($"The mesh at index {i} is not readable.", "meshes");
				}
				num += val.vertexCount;
				num2 += val.subMeshCount;
				Material[] array = materials[i];
				if (array == null)
				{
					throw new ArgumentException($"The materials for mesh at index {i} is null.", "materials");
				}
				if (array.Length != val.subMeshCount)
				{
					throw new ArgumentException($"The materials for mesh at index {i} doesn't match the submesh count ({array.Length} != {val.subMeshCount}).", "materials");
				}
				for (int j = 0; j < array.Length; j++)
				{
					if ((Object)(object)array[j] == (Object)null)
					{
						throw new ArgumentException($"The material at index {j} for mesh at index {i} is null.", "materials");
					}
				}
				if (bones == null)
				{
					continue;
				}
				Transform[] array2 = bones[i];
				if (array2 == null)
				{
					throw new ArgumentException($"The bones for mesh at index {i} is null.", "meshBones");
				}
				for (int k = 0; k < array2.Length; k++)
				{
					if ((Object)(object)array2[k] == (Object)null)
					{
						throw new ArgumentException($"The bone at index {k} for mesh at index {i} is null.", "meshBones");
					}
				}
			}
			List<Vector3> list = new List<Vector3>(num);
			List<int[]> list2 = new List<int[]>(num2);
			List<Vector3> dest = null;
			List<Vector4> dest2 = null;
			List<Color> dest3 = null;
			List<BoneWeight> dest4 = null;
			List<Vector4>[] array3 = new List<Vector4>[MeshUtils.UVChannelCount];
			List<Matrix4x4> list3 = null;
			List<Transform> list4 = null;
			List<Material> list5 = new List<Material>(num2);
			Dictionary<Material, int> dictionary = new Dictionary<Material, int>(num2);
			int num3 = 0;
			for (int l = 0; l < meshes.Length; l++)
			{
				Mesh val2 = meshes[l];
				Matrix4x4 transform = transforms[l];
				Material[] array4 = materials[l];
				Transform[] array5 = ((bones != null) ? bones[l] : null);
				int subMeshCount = val2.subMeshCount;
				int vertexCount = val2.vertexCount;
				Vector3[] vertices = val2.vertices;
				Vector3[] normals = val2.normals;
				Vector4[] tangents = val2.tangents;
				IList<Vector4>[] meshUVs = MeshUtils.GetMeshUVs(val2);
				Color[] colors = val2.colors;
				BoneWeight[] boneWeights = val2.boneWeights;
				Matrix4x4[] bindposes = val2.bindposes;
				if (array5 != null && boneWeights != null && boneWeights.Length != 0 && bindposes != null && bindposes.Length != 0 && array5.Length == bindposes.Length)
				{
					if (list3 == null)
					{
						list3 = new List<Matrix4x4>(bindposes);
						list4 = new List<Transform>(array5);
					}
					int[] array6 = new int[array5.Length];
					for (int m = 0; m < array5.Length; m++)
					{
						int num4 = list4.IndexOf(array5[m]);
						if (num4 == -1 || bindposes[m] != list3[num4])
						{
							num4 = list4.Count;
							list4.Add(array5[m]);
							list3.Add(bindposes[m]);
						}
						array6[m] = num4;
					}
					RemapBones(boneWeights, array6);
				}
				TransformVertices(vertices, ref transform);
				TransformNormals(normals, ref transform);
				TransformTangents(tangents, ref transform);
				CopyVertexPositions(list, vertices);
				CopyVertexAttributes(ref dest, normals, num3, vertexCount, num, new Vector3(1f, 0f, 0f));
				CopyVertexAttributes(ref dest2, tangents, num3, vertexCount, num, new Vector4(0f, 0f, 1f, 1f));
				CopyVertexAttributes(ref dest3, colors, num3, vertexCount, num, new Color(1f, 1f, 1f, 1f));
				CopyVertexAttributes(ref dest4, boneWeights, num3, vertexCount, num, default(BoneWeight));
				for (int n = 0; n < meshUVs.Length; n++)
				{
					CopyVertexAttributes(ref array3[n], meshUVs[n], num3, vertexCount, num, new Vector4(0f, 0f, 0f, 0f));
				}
				for (int num5 = 0; num5 < subMeshCount; num5++)
				{
					Material val3 = array4[num5];
					int[] triangles = val2.GetTriangles(num5, true);
					if (num3 > 0)
					{
						for (int num6 = 0; num6 < triangles.Length; num6++)
						{
							triangles[num6] += num3;
						}
					}
					if (dictionary.TryGetValue(val3, out var value))
					{
						list2[value] = MergeArrays(list2[value], triangles);
						continue;
					}
					int count = list2.Count;
					dictionary.Add(val3, count);
					list5.Add(val3);
					list2.Add(triangles);
				}
				num3 += vertexCount;
			}
			Vector3[] vertices2 = list.ToArray();
			int[][] indices = list2.ToArray();
			Vector3[] normals2 = dest?.ToArray();
			Vector4[] tangents2 = dest2?.ToArray();
			Color[] colors2 = dest3?.ToArray();
			BoneWeight[] boneWeights2 = dest4?.ToArray();
			List<Vector4>[] uvs = array3.ToArray();
			Matrix4x4[] bindposes2 = list3?.ToArray();
			resultMaterials = list5.ToArray();
			resultBones = list4?.ToArray();
			return MeshUtils.CreateMesh(vertices2, indices, normals2, tangents2, colors2, boneWeights2, uvs, bindposes2, null);
		}

		private static void CopyVertexPositions(ICollection<Vector3> list, Vector3[] arr)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (arr != null && arr.Length != 0)
			{
				for (int i = 0; i < arr.Length; i++)
				{
					list.Add(arr[i]);
				}
			}
		}

		private static void CopyVertexAttributes<T>(ref List<T> dest, IEnumerable<T> src, int previousVertexCount, int meshVertexCount, int totalVertexCount, T defaultValue)
		{
			if (src == null || src.Count() == 0)
			{
				if (dest != null)
				{
					for (int i = 0; i < meshVertexCount; i++)
					{
						dest.Add(defaultValue);
					}
				}
				return;
			}
			if (dest == null)
			{
				dest = new List<T>(totalVertexCount);
				for (int j = 0; j < previousVertexCount; j++)
				{
					dest.Add(defaultValue);
				}
			}
			dest.AddRange(src);
		}

		private static T[] MergeArrays<T>(T[] arr1, T[] arr2)
		{
			T[] array = new T[arr1.Length + arr2.Length];
			Array.Copy(arr1, 0, array, 0, arr1.Length);
			Array.Copy(arr2, 0, array, arr1.Length, arr2.Length);
			return array;
		}

		private static void TransformVertices(Vector3[] vertices, ref Matrix4x4 transform)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < vertices.Length; i++)
			{
				vertices[i] = ((Matrix4x4)(ref transform)).MultiplyPoint3x4(vertices[i]);
			}
		}

		private static void TransformNormals(Vector3[] normals, ref Matrix4x4 transform)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (normals != null)
			{
				for (int i = 0; i < normals.Length; i++)
				{
					normals[i] = ((Matrix4x4)(ref transform)).MultiplyVector(normals[i]);
				}
			}
		}

		private static void TransformTangents(Vector4[] tangents, ref Matrix4x4 transform)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (tangents != null)
			{
				for (int i = 0; i < tangents.Length; i++)
				{
					Vector3 val = ((Matrix4x4)(ref transform)).MultiplyVector(new Vector3(tangents[i].x, tangents[i].y, tangents[i].z));
					tangents[i] = new Vector4(val.x, val.y, val.z, tangents[i].w);
				}
			}
		}

		private static void RemapBones(BoneWeight[] boneWeights, int[] boneIndices)
		{
			for (int i = 0; i < boneWeights.Length; i++)
			{
				if (((BoneWeight)(ref boneWeights[i])).weight0 > 0f)
				{
					((BoneWeight)(ref boneWeights[i])).boneIndex0 = boneIndices[((BoneWeight)(ref boneWeights[i])).boneIndex0];
				}
				if (((BoneWeight)(ref boneWeights[i])).weight1 > 0f)
				{
					((BoneWeight)(ref boneWeights[i])).boneIndex1 = boneIndices[((BoneWeight)(ref boneWeights[i])).boneIndex1];
				}
				if (((BoneWeight)(ref boneWeights[i])).weight2 > 0f)
				{
					((BoneWeight)(ref boneWeights[i])).boneIndex2 = boneIndices[((BoneWeight)(ref boneWeights[i])).boneIndex2];
				}
				if (((BoneWeight)(ref boneWeights[i])).weight3 > 0f)
				{
					((BoneWeight)(ref boneWeights[i])).boneIndex3 = boneIndices[((BoneWeight)(ref boneWeights[i])).boneIndex3];
				}
			}
		}

		private static bool CanReadMesh(Mesh mesh)
		{
			return mesh.isReadable;
		}
	}
	public sealed class MeshSimplifier
	{
		private const int TriangleEdgeCount = 3;

		private const int TriangleVertexCount = 3;

		private const double DoubleEpsilon = 0.001;

		private const double DenomEpilson = 1E-08;

		private static readonly int UVChannelCount = MeshUtils.UVChannelCount;

		private SimplificationOptions simplificationOptions = SimplificationOptions.Default;

		private bool verbose;

		private int subMeshCount;

		private int[] subMeshOffsets;

		private ResizableArray<Triangle> triangles;

		private ResizableArray<Vertex> vertices;

		private ResizableArray<Ref> refs;

		private ResizableArray<Vector3> vertNormals;

		private ResizableArray<Vector4> vertTangents;

		private UVChannels<Vector2> vertUV2D;

		private UVChannels<Vector3> vertUV3D;

		private UVChannels<Vector4> vertUV4D;

		private ResizableArray<Color> vertColors;

		private ResizableArray<BoneWeight> vertBoneWeights;

		private ResizableArray<BlendShapeContainer> blendShapes;

		private Matrix4x4[] bindposes;

		private readonly double[] errArr = new double[3];

		private readonly int[] attributeIndexArr = new int[3];

		private readonly HashSet<Triangle> triangleHashSet1 = new HashSet<Triangle>();

		private readonly HashSet<Triangle> triangleHashSet2 = new HashSet<Triangle>();

		public SimplificationOptions SimplificationOptions
		{
			get
			{
				return simplificationOptions;
			}
			set
			{
				ValidateOptions(value);
				simplificationOptions = value;
			}
		}

		[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
		public bool PreserveBorderEdges
		{
			get
			{
				return simplificationOptions.PreserveBorderEdges;
			}
			set
			{
				SimplificationOptions simplificationOptions = this.simplificationOptions;
				simplificationOptions.PreserveBorderEdges = value;
				SimplificationOptions = simplificationOptions;
			}
		}

		[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
		public bool PreserveUVSeamEdges
		{
			get
			{
				return simplificationOptions.PreserveUVSeamEdges;
			}
			set
			{
				SimplificationOptions simplificationOptions = this.simplificationOptions;
				simplificationOptions.PreserveUVSeamEdges = value;
				SimplificationOptions = simplificationOptions;
			}
		}

		[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
		public bool PreserveUVFoldoverEdges
		{
			get
			{
				return simplificationOptions.PreserveUVFoldoverEdges;
			}
			set
			{
				SimplificationOptions simplificationOptions = this.simplificationOptions;
				simplificationOptions.PreserveUVFoldoverEdges = value;
				SimplificationOptions = simplificationOptions;
			}
		}

		[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
		public bool PreserveSurfaceCurvature
		{
			get
			{
				return simplificationOptions.PreserveSurfaceCurvature;
			}
			set
			{
				SimplificationOptions simplificationOptions = this.simplificationOptions;
				simplificationOptions.PreserveSurfaceCurvature = value;
				SimplificationOptions = simplificationOptions;
			}
		}

		[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
		public bool EnableSmartLink
		{
			get
			{
				return simplificationOptions.EnableSmartLink;
			}
			set
			{
				SimplificationOptions simplificationOptions = this.simplificationOptions;
				simplificationOptions.EnableSmartLink = value;
				SimplificationOptions = simplificationOptions;
			}
		}

		[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
		public int MaxIterationCount
		{
			get
			{
				return simplificationOptions.MaxIterationCount;
			}
			set
			{
				SimplificationOptions simplificationOptions = this.simplificationOptions;
				simplificationOptions.MaxIterationCount = value;
				SimplificationOptions = simplificationOptions;
			}
		}

		[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
		public double Agressiveness
		{
			get
			{
				return simplificationOptions.Agressiveness;
			}
			set
			{
				SimplificationOptions simplificationOptions = this.simplificationOptions;
				simplificationOptions.Agressiveness = value;
				SimplificationOptions = simplificationOptions;
			}
		}

		public bool Verbose
		{
			get
			{
				return verbose;
			}
			set
			{
				verbose = value;
			}
		}

		[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
		public double VertexLinkDistance
		{
			get
			{
				return simplificationOptions.VertexLinkDistance;
			}
			set
			{
				SimplificationOptions simplificationOptions = this.simplificationOptions;
				simplificationOptions.VertexLinkDistance = ((value > double.Epsilon) ? value : double.Epsilon);
				SimplificationOptions = simplificationOptions;
			}
		}

		[Obsolete("Use MeshSimplifier.SimplificationOptions instead.", false)]
		public double VertexLinkDistanceSqr
		{
			get
			{
				return simplificationOptions.VertexLinkDistance * simplificationOptions.VertexLinkDistance;
			}
			set
			{
				SimplificationOptions simplificationOptions = this.simplificationOptions;
				simplificationOptions.VertexLinkDistance = Math.Sqrt(value);
				SimplificationOptions = simplificationOptions;
			}
		}

		public Vector3[] Vertices
		{
			get
			{
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				int length = vertices.Length;
				Vector3[] array = (Vector3[])(object)new Vector3[length];
				Vertex[] data = vertices.Data;
				for (int i = 0; i < length; i++)
				{
					array[i] = (Vector3)data[i].p;
				}
				return array;
			}
			set
			{
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}
				bindposes = null;
				vertices.Resize(value.Length);
				Vertex[] data = vertices.Data;
				for (int i = 0; i < value.Length; i++)
				{
					data[i] = new Vertex(i, value[i]);
				}
			}
		}

		public int SubMeshCount => subMeshCount;

		public int BlendShapeCount
		{
			get
			{
				if (blendShapes == null)
				{
					return 0;
				}
				return blendShapes.Length;
			}
		}

		public Vector3[] Normals
		{
			get
			{
				if (vertNormals == null)
				{
					return null;
				}
				return vertNormals.Data;
			}
			set
			{
				InitializeVertexAttribute(value, ref vertNormals, "normals");
			}
		}

		public Vector4[] Tangents
		{
			get
			{
				if (vertTangents == null)
				{
					return null;
				}
				return vertTangents.Data;
			}
			set
			{
				InitializeVertexAttribute(value, ref vertTangents, "tangents");
			}
		}

		public Vector2[] UV1
		{
			get
			{
				return GetUVs2D(0);
			}
			set
			{
				SetUVs(0, value);
			}
		}

		public Vector2[] UV2
		{
			get
			{
				return GetUVs2D(1);
			}
			set
			{
				SetUVs(1, value);
			}
		}

		public Vector2[] UV3
		{
			get
			{
				return GetUVs2D(2);
			}
			set
			{
				SetUVs(2, value);
			}
		}

		public Vector2[] UV4
		{
			get
			{
				return GetUVs2D(3);
			}
			set
			{
				SetUVs(3, value);
			}
		}

		public Color[] Colors
		{
			get
			{
				if (vertColors == null)
				{
					return null;
				}
				return vertColors.Data;
			}
			set
			{
				InitializeVertexAttribute(value, ref vertColors, "colors");
			}
		}

		public BoneWeight[] BoneWeights
		{
			get
			{
				if (vertBoneWeights == null)
				{
					return null;
				}
				return vertBoneWeights.Data;
			}
			set
			{
				InitializeVertexAttribute(value, ref vertBoneWeights, "boneWeights");
			}
		}

		public MeshSimplifier()
		{
			triangles = new ResizableArray<Triangle>(0);
			vertices = new ResizableArray<Vertex>(0);
			refs = new ResizableArray<Ref>(0);
		}

		public MeshSimplifier(Mesh mesh)
			: this()
		{
			if ((Object)(object)mesh != (Object)null)
			{
				Initialize(mesh);
			}
		}

		private void InitializeVertexAttribute<T>(T[] attributeValues, ref ResizableArray<T> attributeArray, string attributeName)
		{
			if (attributeValues != null && attributeValues.Length == vertices.Length)
			{
				if (attributeArray == null)
				{
					attributeArray = new ResizableArray<T>(attributeValues.Length, attributeValues.Length);
				}
				else
				{
					attributeArray.Resize(attributeValues.Length);
				}
				T[] data = attributeArray.Data;
				Array.Copy(attributeValues, 0, data, 0, attributeValues.Length);
				return;
			}
			if (attributeValues != null && attributeValues.Length != 0)
			{
				Debug.LogErrorFormat("Failed to set vertex attribute '{0}' with {1} length of array, when {2} was needed.", new object[3] { attributeName, attributeValues.Length, vertices.Length });
			}
			attributeArray = null;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static double VertexError(ref SymmetricMatrix q, double x, double y, double z)
		{
			return q.m0 * x * x + 2.0 * q.m1 * x * y + 2.0 * q.m2 * x * z + 2.0 * q.m3 * x + q.m4 * y * y + 2.0 * q.m5 * y * z + 2.0 * q.m6 * y + q.m7 * z * z + 2.0 * q.m8 * z + q.m9;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private double CurvatureError(ref Vertex vert0, ref Vertex vert1)
		{
			double magnitude = (vert0.p - vert1.p).Magnitude;
			HashSet<Triangle> hashSet = triangleHashSet1;
			hashSet.Clear();
			GetTrianglesContainingVertex(ref vert0, hashSet);
			GetTrianglesContainingVertex(ref vert1, hashSet);
			HashSet<Triangle> hashSet2 = triangleHashSet2;
			hashSet2.Clear();
			GetTrianglesContainingBothVertices(ref vert0, ref vert1, hashSet2);
			double num = 0.0;
			foreach (Triangle item in hashSet)
			{
				double num2 = 0.0;
				Vector3d lhs = item.n;
				foreach (Triangle item2 in hashSet2)
				{
					Vector3d rhs = item2.n;
					double num3 = Vector3d.Dot(ref lhs, ref rhs);
					if (num3 > num2)
					{
						num2 = num3;
					}
				}
				if (num2 > num)
				{
					num = num2;
				}
			}
			return magnitude * num;
		}

		private double CalculateError(ref Vertex vert0, ref Vertex vert1, out Vector3d result)
		{
			SymmetricMatrix q = vert0.q + vert1.q;
			bool flag = vert0.borderEdge && vert1.borderEdge;
			double num = 0.0;
			double num2 = q.Determinant1();
			if (num2 != 0.0 && !flag)
			{
				result = new Vector3d(-1.0 / num2 * q.Determinant2(), 1.0 / num2 * q.Determinant3(), -1.0 / num2 * q.Determinant4());
				double num3 = 0.0;
				if (simplificationOptions.PreserveSurfaceCurvature)
				{
					num3 = CurvatureError(ref vert0, ref vert1);
				}
				num = VertexError(ref q, result.x, result.y, result.z) + num3;
			}
			else
			{
				Vector3d p = vert0.p;
				Vector3d p2 = vert1.p;
				Vector3d vector3d = (p + p2) * 0.5;
				double num4 = VertexError(ref q, p.x, p.y, p.z);
				double num5 = VertexError(ref q, p2.x, p2.y, p2.z);
				double num6 = VertexError(ref q, vector3d.x, vector3d.y, vector3d.z);
				if (num4 < num5)
				{
					if (num4 < num6)
					{
						num = num4;
						result = p;
					}
					else
					{
						num = num6;
						result = vector3d;
					}
				}
				else if (num5 < num6)
				{
					num = num5;
					result = p2;
				}
				else
				{
					num = num6;
					result = vector3d;
				}
			}
			return num;
		}

		private static void CalculateBarycentricCoords(ref Vector3d point, ref Vector3d a, ref Vector3d b, ref Vector3d c, out Vector3 result)
		{
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			Vector3d lhs = b - a;
			Vector3d rhs = c - a;
			Vector3d lhs2 = point - a;
			double num = Vector3d.Dot(ref lhs, ref lhs);
			double num2 = Vector3d.Dot(ref lhs, ref rhs);
			double num3 = Vector3d.Dot(ref rhs, ref rhs);
			double num4 = Vector3d.Dot(ref lhs2, ref lhs);
			double num5 = Vector3d.Dot(ref lhs2, ref rhs);
			double num6 = num * num3 - num2 * num2;
			if (Math.Abs(num6) < 1E-08)
			{
				num6 = 1E-08;
			}
			double num7 = (num3 * num4 - num2 * num5) / num6;
			double num8 = (num * num5 - num2 * num4) / num6;
			double num9 = 1.0 - num7 - num8;
			result = new Vector3((float)num9, (float)num7, (float)num8);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static Vector4 NormalizeTangent(Vector4 tangent)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(tangent.x, tangent.y, tangent.z);
			((Vector3)(ref val)).Normalize();
			return new Vector4(val.x, val.y, val.z, tangent.w);
		}

		private bool Flipped(ref Vector3d p, int i0, int i1, ref Vertex v0, bool[] deleted)
		{
			int tcount = v0.tcount;
			Ref[] data = refs.Data;
			Triangle[] data2 = triangles.Data;
			Vertex[] data3 = vertices.Data;
			for (int j = 0; j < tcount; j++)
			{
				Ref obj = data[v0.tstart + j];
				if (data2[obj.tid].deleted)
				{
					continue;
				}
				int tvertex = obj.tvertex;
				int num = data2[obj.tid][(tvertex + 1) % 3];
				int num2 = data2[obj.tid][(tvertex + 2) % 3];
				if (num == i1 || num2 == i1)
				{
					deleted[j] = true;
					continue;
				}
				Vector3d lhs = data3[num].p - p;
				lhs.Normalize();
				Vector3d rhs = data3[num2].p - p;
				rhs.Normalize();
				if (Math.Abs(Vector3d.Dot(ref lhs, ref rhs)) > 0.999)
				{
					return true;
				}
				Vector3d.Cross(ref lhs, ref rhs, out var result);
				result.Normalize();
				deleted[j] = false;
				if (Vector3d.Dot(ref result, ref data2[obj.tid].n) < 0.2)
				{
					return true;
				}
			}
			return false;
		}

		private void UpdateTriangles(int i0, int ia0, ref Vertex v, ResizableArray<bool> deleted, ref int deletedTriangles)
		{
			int tcount = v.tcount;
			Triangle[] data = triangles.Data;
			Vertex[] data2 = vertices.Data;
			for (int j = 0; j < tcount; j++)
			{
				Ref item = refs[v.tstart + j];
				int tid = item.tid;
				Triangle triangle = data[tid];
				if (triangle.deleted)
				{
					continue;
				}
				if (deleted[j])
				{
					data[tid].deleted = true;
					deletedTriangles++;
					continue;
				}
				triangle[item.tvertex] = i0;
				if (ia0 != -1)
				{
					triangle.SetAttributeIndex(item.tvertex, ia0);
				}
				triangle.dirty = true;
				triangle.err0 = CalculateError(ref data2[triangle.v0], ref data2[triangle.v1], out var result);
				triangle.err1 = CalculateError(ref data2[triangle.v1], ref data2[triangle.v2], out result);
				triangle.err2 = CalculateError(ref data2[triangle.v2], ref data2[triangle.v0], out result);
				triangle.err3 = MathHelper.Min(triangle.err0, triangle.err1, triangle.err2);
				data[tid] = triangle;
				refs.Add(item);
			}
		}

		private void InterpolateVertexAttributes(int dst, int i0, int i1, int i2, ref Vector3 barycentricCoord)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			if (vertNormals != null)
			{
				vertNormals[dst] = Vector3.Normalize(vertNormals[i0] * barycentricCoord.x + vertNormals[i1] * barycentricCoord.y + vertNormals[i2] * barycentricCoord.z);
			}
			if (vertTangents != null)
			{
				vertTangents[dst] = NormalizeTangent(vertTangents[i0] * barycentricCoord.x + vertTangents[i1] * barycentricCoord.y + vertTangents[i2] * barycentricCoord.z);
			}
			if (vertUV2D != null)
			{
				for (int j = 0; j < UVChannelCount; j++)
				{
					ResizableArray<Vector2> resizableArray = vertUV2D[j];
					if (resizableArray != null)
					{
						resizableArray[dst] = resizableArray[i0] * barycentricCoord.x + resizableArray[i1] * barycentricCoord.y + resizableArray[i2] * barycentricCoord.z;
					}
				}
			}
			if (vertUV3D != null)
			{
				for (int k = 0; k < UVChannelCount; k++)
				{
					ResizableArray<Vector3> resizableArray2 = vertUV3D[k];
					if (resizableArray2 != null)
					{
						resizableArray2[dst] = resizableArray2[i0] * barycentricCoord.x + resizableArray2[i1] * barycentricCoord.y + resizableArray2[i2] * barycentricCoord.z;
					}
				}
			}
			if (vertUV4D != null)
			{
				for (int l = 0; l < UVChannelCount; l++)
				{
					ResizableArray<Vector4> resizableArray3 = vertUV4D[l];
					if (resizableArray3 != null)
					{
						resizableArray3[dst] = resizableArray3[i0] * barycentricCoord.x + resizableArray3[i1] * barycentricCoord.y + resizableArray3[i2] * barycentricCoord.z;
					}
				}
			}
			if (vertColors != null)
			{
				vertColors[dst] = vertColors[i0] * barycentricCoord.x + vertColors[i1] * barycentricCoord.y + vertColors[i2] * barycentricCoord.z;
			}
			if (blendShapes != null)
			{
				for (int m = 0; m < blendShapes.Length; m++)
				{
					blendShapes[m].InterpolateVertexAttributes(dst, i0, i1, i2, ref barycentricCoord);
				}
			}
		}

		private bool AreUVsTheSame(int channel, int indexA, int indexB)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if (vertUV2D != null)
			{
				ResizableArray<Vector2> resizableArray = vertUV2D[channel];
				if (resizableArray != null)
				{
					Vector2 val = resizableArray[indexA];
					Vector2 val2 = resizableArray[indexB];
					return val == val2;
				}
			}
			if (vertUV3D != null)
			{
				ResizableArray<Vector3> resizableArray2 = vertUV3D[channel];
				if (resizableArray2 != null)
				{
					Vector3 val3 = resizableArray2[indexA];
					Vector3 val4 = resizableArray2[indexB];
					return val3 == val4;
				}
			}
			if (vertUV4D != null)
			{
				ResizableArray<Vector4> resizableArray3 = vertUV4D[channel];
				if (resizableArray3 != null)
				{
					Vector4 val5 = resizableArray3[indexA];
					Vector4 val6 = resizableArray3[indexB];
					return val5 == val6;
				}
			}
			return false;
		}

		private void RemoveVertexPass(int startTrisCount, int targetTrisCount, double threshold, ResizableArray<bool> deleted0, ResizableArray<bool> deleted1, ref int deletedTris)
		{
			Triangle[] data = triangles.Data;
			int length = triangles.Length;
			Vertex[] data2 = vertices.Data;
			for (int i = 0; i < length; i++)
			{
				if (data[i].dirty || data[i].deleted || data[i].err3 > threshold)
				{
					continue;
				}
				data[i].GetErrors(errArr);
				data[i].GetAttributeIndices(attributeIndexArr);
				for (int j = 0; j < 3; j++)
				{
					if (errArr[j] > threshold)
					{
						continue;
					}
					int num = (j + 1) % 3;
					int num2 = data[i][j];
					int num3 = data[i][num];
					if (data2[num2].borderEdge != data2[num3].borderEdge || data2[num2].uvSeamEdge != data2[num3].uvSeamEdge || data2[num2].uvFoldoverEdge != data2[num3].uvFoldoverEdge || (simplificationOptions.PreserveBorderEdges && data2[num2].borderEdge) || (simplificationOptions.PreserveUVSeamEdges && data2[num2].uvSeamEdge) || (simplificationOptions.PreserveUVFoldoverEdges && data2[num2].uvFoldoverEdge))
					{
						continue;
					}
					CalculateError(ref data2[num2], ref data2[num3], out var result);
					deleted0.Resize(data2[num2].tcount);
					deleted1.Resize(data2[num3].tcount);
					if (Flipped(ref result, num2, num3, ref data2[num2], deleted0.Data) || Flipped(ref result, num3, num2, ref data2[num3], deleted1.Data))
					{
						continue;
					}
					int num4 = (j + 2) % 3;
					int num5 = data[i][num4];
					CalculateBarycentricCoords(ref result, ref data2[num2].p, ref data2[num3].p, ref data2[num5].p, out var result2);
					data2[num2].p = result;
					data2[num2].q += data2[num3].q;
					int num6 = attributeIndexArr[j];
					int i2 = attributeIndexArr[num];
					int i3 = attributeIndexArr[num4];
					InterpolateVertexAttributes(num6, num6, i2, i3, ref result2);
					if (data2[num2].uvSeamEdge)
					{
						num6 = -1;
					}
					int length2 = refs.Length;
					UpdateTriangles(num2, num6, ref data2[num2], deleted0, ref deletedTris);
					UpdateTriangles(num2, num6, ref data2[num3], deleted1, ref deletedTris);
					int num7 = refs.Length - length2;
					if (num7 <= data2[num2].tcount)
					{
						if (num7 > 0)
						{
							Ref[] data3 = refs.Data;
							Array.Copy(data3, length2, data3, data2[num2].tstart, num7);
						}
					}
					else
					{
						data2[num2].tstart = length2;
					}
					data2[num2].tcount = num7;
					break;
				}
				if (startTrisCount - deletedTris <= targetTrisCount)
				{
					break;
				}
			}
		}

		private void UpdateMesh(int iteration)
		{
			Triangle[] data = triangles.Data;
			Vertex[] data2 = vertices.Data;
			int num = triangles.Length;
			int length = vertices.Length;
			if (iteration > 0)
			{
				int num2 = 0;
				for (int i = 0; i < num; i++)
				{
					if (!data[i].deleted)
					{
						if (num2 != i)
						{
							data[num2] = data[i];
							data[num2].index = num2;
						}
						num2++;
					}
				}
				triangles.Resize(num2);
				data = triangles.Data;
				num = num2;
			}
			UpdateReferences();
			if (iteration != 0)
			{
				return;
			}
			Ref[] data3 = refs.Data;
			List<int> list = new List<int>(8);
			List<int> list2 = new List<int>(8);
			int num3 = 0;
			for (int j = 0; j < length; j++)
			{
				data2[j].borderEdge = false;
				data2[j].uvSeamEdge = false;
				data2[j].uvFoldoverEdge = false;
			}
			int num4 = 0;
			double num5 = double.MaxValue;
			double num6 = double.MinValue;
			double num7 = simplificationOptions.VertexLinkDistance * simplificationOptions.VertexLinkDistance;
			for (int k = 0; k < length; k++)
			{
				int tstart = data2[k].tstart;
				int tcount = data2[k].tcount;
				list.Clear();
				list2.Clear();
				num3 = 0;
				for (int l = 0; l < tcount; l++)
				{
					int tid = data3[tstart + l].tid;
					for (int m = 0; m < 3; m++)
					{
						int n = 0;
						int num8;
						for (num8 = data[tid][m]; n < num3 && list2[n] != num8; n++)
						{
						}
						if (n == num3)
						{
							list.Add(1);
							list2.Add(num8);
							num3++;
						}
						else
						{
							int index = n;
							int value = list[index] + 1;
							list[index] = value;
						}
					}
				}
				for (int num9 = 0; num9 < num3; num9++)
				{
					if (list[num9] != 1)
					{
						continue;
					}
					int num8 = list2[num9];
					data2[num8].borderEdge = true;
					num4++;
					if (simplificationOptions.EnableSmartLink)
					{
						if (data2[num8].p.x < num5)
						{
							num5 = data2[num8].p.x;
						}
						if (data2[num8].p.x > num6)
						{
							num6 = data2[num8].p.x;
						}
					}
				}
			}
			if (simplificationOptions.EnableSmartLink)
			{
				BorderVertex[] array = new BorderVertex[num4];
				int num10 = 0;
				double num11 = num6 - num5;
				for (int num12 = 0; num12 < length; num12++)
				{
					if (data2[num12].borderEdge)
					{
						int hash = (int)(((data2[num12].p.x - num5) / num11 * 2.0 - 1.0) * 2147483647.0);
						array[num10] = new BorderVertex(num12, hash);
						num10++;
					}
				}
				Array.Sort(array, 0, num10, BorderVertexComparer.instance);
				int num13 = Math.Max((int)(Math.Sqrt(num7) / num11 * 2147483647.0), 1);
				for (int num14 = 0; num14 < num10; num14++)
				{
					int index2 = array[num14].index;
					if (index2 == -1)
					{
						continue;
					}
					Vector3d p = data2[index2].p;
					for (int num15 = num14 + 1; num15 < num10; num15++)
					{
						int index3 = array[num15].index;
						if (index3 == -1)
						{
							continue;
						}
						if (array[num15].hash - array[num14].hash > num13)
						{
							break;
						}
						Vector3d p2 = data2[index3].p;
						double num16 = (p.x - p2.x) * (p.x - p2.x);
						double num17 = (p.y - p2.y) * (p.y - p2.y);
						double num18 = (p.z - p2.z) * (p.z - p2.z);
						if (num16 + num17 + num18 <= num7)
						{
							array[num15].index = -1;
							data2[index2].borderEdge = false;
							data2[index3].borderEdge = false;
							if (AreUVsTheSame(0, index2, index3))
							{
								data2[index2].uvFoldoverEdge = true;
								data2[index3].uvFoldoverEdge = true;
							}
							else
							{
								data2[index2].uvSeamEdge = true;
								data2[index3].uvSeamEdge = true;
							}
							int tcount2 = data2[index3].tcount;
							int tstart2 = data2[index3].tstart;
							for (int num19 = 0; num19 < tcount2; num19++)
							{
								Ref obj = data3[tstart2 + num19];
								data[obj.tid][obj.tvertex] = index2;
							}
						}
					}
				}
				UpdateReferences();
			}
			for (int num20 = 0; num20 < length; num20++)
			{
				data2[num20].q = default(SymmetricMatrix);
			}
			for (int num21 = 0; num21 < num; num21++)
			{
				int v = data[num21].v0;
				int v2 = data[num21].v1;
				int v3 = data[num21].v2;
				Vector3d rhs = data2[v].p;
				Vector3d p3 = data2[v2].p;
				Vector3d p4 = data2[v3].p;
				Vector3d lhs = p3 - rhs;
				Vector3d rhs2 = p4 - rhs;
				Vector3d.Cross(ref lhs, ref rhs2, out var result);
				result.Normalize();
				data[num21].n = result;
				SymmetricMatrix symmetricMatrix = new SymmetricMatrix(result.x, result.y, result.z, 0.0 - Vector3d.Dot(ref result, ref rhs));
				data2[v].q += symmetricMatrix;
				data2[v2].q += symmetricMatrix;
				data2[v3].q += symmetricMatrix;
			}
			for (int num22 = 0; num22 < num; num22++)
			{
				Triangle triangle = data[num22];
				data[num22].err0 = CalculateError(ref data2[triangle.v0], ref data2[triangle.v1], out var result2);
				data[num22].err1 = CalculateError(ref data2[triangle.v1], ref data2[triangle.v2], out result2);
				data[num22].err2 = CalculateError(ref data2[triangle.v2], ref data2[triangle.v0], out result2);
				data[num22].err3 = MathHelper.Min(data[num22].err0, data[num22].err1, data[num22].err2);
			}
		}

		private void UpdateReferences()
		{
			int length = triangles.Length;
			int length2 = vertices.Length;
			Triangle[] data = triangles.Data;
			Vertex[] data2 = vertices.Data;
			for (int i = 0; i < length2; i++)
			{
				data2[i].tstart = 0;
				data2[i].tcount = 0;
			}
			for (int j = 0; j < length; j++)
			{
				data2[data[j].v0].tcount++;
				data2[data[j].v1].tcount++;
				data2[data[j].v2].tcount++;
			}
			int num = 0;
			for (int k = 0; k < length2; k++)
			{
				data2[k].tstart = num;
				num += data2[k].tcount;
				data2[k].tcount = 0;
			}
			refs.Resize(num);
			Ref[] data3 = refs.Data;
			for (int l = 0; l < length; l++)
			{
				int v = data[l].v0;
				int v2 = data[l].v1;
				int v3 = data[l].v2;
				int tstart = data2[v].tstart;
				int num2 = data2[v].tcount++;
				int tstart2 = data2[v2].tstart;
				int num3 = data2[v2].tcount++;
				int tstart3 = data2[v3].tstart;
				int num4 = data2[v3].tcount++;
				data3[tstart + num2].Set(l, 0);
				data3[tstart2 + num3].Set(l, 1);
				data3[tstart3 + num4].Set(l, 2);
			}
		}

		private void CompactMesh()
		{
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_047d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0482: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0492: Unknown result type (might be due to invalid IL or missing references)
			//IL_0497: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_042a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0459: Unknown result type (might be due to invalid IL or missing references)
			//IL_045e: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			Vertex[] data = vertices.Data;
			int length = vertices.Length;
			for (int i = 0; i < length; i++)
			{
				data[i].tcount = 0;
			}
			Vector3[] array = ((vertNormals != null) ? vertNormals.Data : null);
			Vector4[] array2 = ((vertTangents != null) ? vertTangents.Data : null);
			Vector2[][] array3 = ((vertUV2D != null) ? vertUV2D.Data : null);
			Vector3[][] array4 = ((vertUV3D != null) ? vertUV3D.Data : null);
			Vector4[][] array5 = ((vertUV4D != null) ? vertUV4D.Data : null);
			Color[] array6 = ((vertColors != null) ? vertColors.Data : null);
			BoneWeight[] array7 = ((vertBoneWeights != null) ? vertBoneWeights.Data : null);
			BlendShapeContainer[] array8 = ((blendShapes != null) ? blendShapes.Data : null);
			int num2 = -1;
			subMeshOffsets = new int[subMeshCount];
			Triangle[] data2 = triangles.Data;
			int length2 = triangles.Length;
			for (int j = 0; j < length2; j++)
			{
				Triangle triangle = data2[j];
				if (triangle.deleted)
				{
					continue;
				}
				if (triangle.va0 != triangle.v0)
				{
					int va = triangle.va0;
					int v = triangle.v0;
					data[va].p = data[v].p;
					if (array7 != null)
					{
						array7[va] = array7[v];
					}
					triangle.v0 = triangle.va0;
				}
				if (triangle.va1 != triangle.v1)
				{
					int va2 = triangle.va1;
					int v2 = triangle.v1;
					data[va2].p = data[v2].p;
					if (array7 != null)
					{
						array7[va2] = array7[v2];
					}
					triangle.v1 = triangle.va1;
				}
				if (triangle.va2 != triangle.v2)
				{
					int va3 = triangle.va2;
					int v3 = triangle.v2;
					data[va3].p = data[v3].p;
					if (array7 != null)
					{
						array7[va3] = array7[v3];
					}
					triangle.v2 = triangle.va2;
				}
				int num3 = num++;
				data2[num3] = triangle;
				data2[num3].index = num3;
				data[triangle.v0].tcount = 1;
				data[triangle.v1].tcount = 1;
				data[triangle.v2].tcount = 1;
				if (triangle.subMeshIndex > num2)
				{
					for (int k = num2 + 1; k < triangle.subMeshIndex; k++)
					{
						subMeshOffsets[k] = num3;
					}
					subMeshOffsets[triangle.subMeshIndex] = num3;
					num2 = triangle.subMeshIndex;
				}
			}
			length2 = num;
			for (int l = num2 + 1; l < subMeshCount; l++)
			{
				subMeshOffsets[l] = length2;
			}
			triangles.Resize(length2);
			data2 = triangles.Data;
			num = 0;
			for (int m = 0; m < length; m++)
			{
				Vertex vertex = data[m];
				if (vertex.tcount <= 0)
				{
					continue;
				}
				data[m].tstart = num;
				if (num != m)
				{
					data[num].index = num;
					data[num].p = vertex.p;
					if (array != null)
					{
						array[num] = array[m];
					}
					if (array2 != null)
					{
						array2[num] = array2[m];
					}
					if (array3 != null)
					{
						for (int n = 0; n < UVChannelCount; n++)
						{
							Vector2[] array9 = array3[n];
							if (array9 != null)
							{
								array9[num] = array9[m];
							}
						}
					}
					if (array4 != null)
					{
						for (int num4 = 0; num4 < UVChannelCount; num4++)
						{
							Vector3[] array10 = array4[num4];
							if (array10 != null)
							{
								array10[num] = array10[m];
							}
						}
					}
					if (array5 != null)
					{
						for (int num5 = 0; num5 < UVChannelCount; num5++)
						{
							Vector4[] array11 = array5[num5];
							if (array11 != null)
							{
								array11[num] = array11[m];
							}
						}
					}
					if (array6 != null)
					{
						array6[num] = array6[m];
					}
					if (array7 != null)
					{
						array7[num] = array7[m];
					}
					if (array8 != null)
					{
						for (int num6 = 0; num6 < blendShapes.Length; num6++)
						{
							array8[num6].MoveVertexElement(num, m);
						}
					}
				}
				num++;
			}
			for (int num7 = 0; num7 < length2; num7++)
			{
				Triangle triangle2 = data2[num7];
				triangle2.v0 = data[triangle2.v0].tstart;
				triangle2.v1 = data[triangle2.v1].tstart;
				triangle2.v2 = data[triangle2.v2].tstart;
				data2[num7] = triangle2;
			}
			length = num;
			vertices.Resize(length);
			if (array != null)
			{
				vertNormals.Resize(length, trimExess: true);
			}
			if (array2 != null)
			{
				vertTangents.Resize(length, trimExess: true);
			}
			if (array3 != null)
			{
				vertUV2D.Resize(length, trimExess: true);
			}
			if (array4 != null)
			{
				vertUV3D.Resize(length, trimExess: true);
			}
			if (array5 != null)
			{
				vertUV4D.Resize(length, trimExess: true);
			}
			if (array6 != null)
			{
				vertColors.Resize(length, trimExess: true);
			}
			if (array7 != null)
			{
				vertBoneWeights.Resize(length, trimExess: true);
			}
			if (array8 != null)
			{
				for (int num8 = 0; num8 < blendShapes.Length; num8++)
				{
					array8[num8].Resize(length);
				}
			}
		}

		private void CalculateSubMeshOffsets()
		{
			int num = -1;
			subMeshOffsets = new int[subMeshCount];
			Triangle[] data = triangles.Data;
			int length = triangles.Length;
			for (int i = 0; i < length; i++)
			{
				Triangle triangle = data[i];
				if (triangle.subMeshIndex > num)
				{
					for (int j = num + 1; j < triangle.subMeshIndex; j++)
					{
						subMeshOffsets[j] = i;
					}
					subMeshOffsets[triangle.subMeshIndex] = i;
					num = triangle.subMeshIndex;
				}
			}
			for (int k = num + 1; k < subMeshCount; k++)
			{
				subMeshOffsets[k] = length;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private void GetTrianglesContainingVertex(ref Vertex vert, HashSet<Triangle> tris)
		{
			int tcount = vert.tcount;
			int tstart = vert.tstart;
			for (int i = tstart; i < tstart + tcount; i++)
			{
				tris.Add(triangles[refs[i].tid]);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private void GetTrianglesContainingBothVertices(ref Vertex vert0, ref Vertex vert1, HashSet<Triangle> tris)
		{
			int tcount = vert0.tcount;
			int tstart = vert0.tstart;
			for (int i = tstart; i < tstart + tcount; i++)
			{
				int tid = refs[i].tid;
				Triangle item = triangles[tid];
				if (vertices[item.v0].index == vert1.index || vertices[item.v1].index == vert1.index || vertices[item.v2].index == vert1.index)
				{
					tris.Add(item);
				}
			}
		}

		public int[][] GetAllSubMeshTriangles()
		{
			int[][] array = new int[subMeshCount][];
			for (int i = 0; i < subMeshCount; i++)
			{
				array[i] = GetSubMeshTriangles(i);
			}
			return array;
		}

		public int[] GetSubMeshTriangles(int subMeshIndex)
		{
			if (subMeshIndex < 0)
			{
				throw new ArgumentOutOfRangeException("subMeshIndex", "The sub-mesh index is negative.");
			}
			if (subMeshOffsets == null)
			{
				CalculateSubMeshOffsets();
			}
			if (subMeshIndex >= subMeshOffsets.Length)
			{
				throw new ArgumentOutOfRangeException("subMeshIndex", "The sub-mesh index is greater than or equals to the sub mesh count.");
			}
			if (subMeshOffsets.Length != subMeshCount)
			{
				throw new InvalidOperationException("The sub-mesh triangle offsets array is not the same size as the count of sub-meshes. This should not be possible to happen.");
			}
			Triangle[] data = triangles.Data;
			int length = triangles.Length;
			int num = subMeshOffsets[subMeshIndex];
			if (num >= length)
			{
				return new int[0];
			}
			int num2 = ((subMeshIndex + 1 < subMeshCount) ? subMeshOffsets[subMeshIndex + 1] : length);
			int num3 = num2 - num;
			if (num3 < 0)
			{
				num3 = 0;
			}
			int[] array = new int[num3 * 3];
			for (int i = num; i < num2; i++)
			{
				Triangle triangle = data[i];
				int num4 = (i - num) * 3;
				array[num4] = triangle.v0;
				array[num4 + 1] = triangle.v1;
				array[num4 + 2] = triangle.v2;
			}
			return array;
		}

		public void ClearSubMeshes()
		{
			subMeshCount = 0;
			subMeshOffsets = null;
			triangles.Resize(0);
		}

		public void AddSubMeshTriangles(int[] triangles)
		{
			if (triangles == null)
			{
				throw new ArgumentNullException("triangles");
			}
			if (triangles.Length % 3 != 0)
			{
				throw new ArgumentException("The index array length must be a multiple of 3 in order to represent triangles.", "triangles");
			}
			int subMeshIndex = subMeshCount++;
			int length = this.triangles.Length;
			int num = triangles.Length / 3;
			this.triangles.Resize(this.triangles.Length + num);
			Triangle[] data = this.triangles.Data;
			for (int i = 0; i < num; i++)
			{
				int num2 = i * 3;
				int v = triangles[num2];
				int v2 = triangles[num2 + 1];
				int v3 = triangles[num2 + 2];
				int num3 = length + i;
				data[num3] = new Triangle(num3, v, v2, v3, subMeshIndex);
			}
		}

		public void AddSubMeshTriangles(int[][] triangles)
		{
			if (triangles == null)
			{
				throw new ArgumentNullException("triangles");
			}
			int num = 0;
			for (int i = 0; i < triangles.Length; i++)
			{
				if (triangles[i] == null)
				{
					throw new ArgumentException($"The index array at index {i} is null.");
				}
				if (triangles[i].Length % 3 != 0)
				{
					throw new ArgumentException($"The index array length at index {i} must be a multiple of 3 in order to represent triangles.", "triangles");
				}
				num += triangles[i].Length / 3;
			}
			int num2 = this.triangles.Length;
			this.triangles.Resize(this.triangles.Length + num);
			Triangle[] data = this.triangles.Data;
			for (int j = 0; j < triangles.Length; j++)
			{
				int subMeshIndex = subMeshCount++;
				int[] array = triangles[j];
				int num3 = array.Length / 3;
				for (int k = 0; k < num3; k++)
				{
					int num4 = k * 3;
					int v = array[num4];
					int v2 = array[num4 + 1];
					int v3 = array[num4 + 2];
					int num5 = num2 + k;
					data[num5] = new Triangle(num5, v, v2, v3, subMeshIndex);
				}
				num2 += num3;
			}
		}

		public Vector2[] GetUVs2D(int channel)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (vertUV2D != null && vertUV2D[channel] != null)
			{
				return vertUV2D[channel].Data;
			}
			return null;
		}

		public Vector3[] GetUVs3D(int channel)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (vertUV3D != null && vertUV3D[channel] != null)
			{
				return vertUV3D[channel].Data;
			}
			return null;
		}

		public Vector4[] GetUVs4D(int channel)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (vertUV4D != null && vertUV4D[channel] != null)
			{
				return vertUV4D[channel].Data;
			}
			return null;
		}

		public void GetUVs(int channel, List<Vector2> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvs == null)
			{
				throw new ArgumentNullException("uvs");
			}
			uvs.Clear();
			if (vertUV2D != null && vertUV2D[channel] != null)
			{
				Vector2[] data = vertUV2D[channel].Data;
				if (data != null)
				{
					uvs.AddRange(data);
				}
			}
		}

		public void GetUVs(int channel, List<Vector3> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvs == null)
			{
				throw new ArgumentNullException("uvs");
			}
			uvs.Clear();
			if (vertUV3D != null && vertUV3D[channel] != null)
			{
				Vector3[] data = vertUV3D[channel].Data;
				if (data != null)
				{
					uvs.AddRange(data);
				}
			}
		}

		public void GetUVs(int channel, List<Vector4> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvs == null)
			{
				throw new ArgumentNullException("uvs");
			}
			uvs.Clear();
			if (vertUV4D != null && vertUV4D[channel] != null)
			{
				Vector4[] data = vertUV4D[channel].Data;
				if (data != null)
				{
					uvs.AddRange(data);
				}
			}
		}

		public void SetUVs(int channel, IList<Vector2> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvs != null && uvs.Count > 0)
			{
				if (vertUV2D == null)
				{
					vertUV2D = new UVChannels<Vector2>();
				}
				int count = uvs.Count;
				ResizableArray<Vector2> resizableArray = vertUV2D[channel];
				if (resizableArray != null)
				{
					resizableArray.Resize(count);
				}
				else
				{
					resizableArray = new ResizableArray<Vector2>(count, count);
					vertUV2D[channel] = resizableArray;
				}
				Vector2[] data = resizableArray.Data;
				uvs.CopyTo(data, 0);
			}
			else if (vertUV2D != null)
			{
				vertUV2D[channel] = null;
			}
			if (vertUV3D != null)
			{
				vertUV3D[channel] = null;
			}
			if (vertUV4D != null)
			{
				vertUV4D[channel] = null;
			}
		}

		public void SetUVs(int channel, IList<Vector3> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvs != null && uvs.Count > 0)
			{
				if (vertUV3D == null)
				{
					vertUV3D = new UVChannels<Vector3>();
				}
				int count = uvs.Count;
				ResizableArray<Vector3> resizableArray = vertUV3D[channel];
				if (resizableArray != null)
				{
					resizableArray.Resize(count);
				}
				else
				{
					resizableArray = new ResizableArray<Vector3>(count, count);
					vertUV3D[channel] = resizableArray;
				}
				Vector3[] data = resizableArray.Data;
				uvs.CopyTo(data, 0);
			}
			else if (vertUV3D != null)
			{
				vertUV3D[channel] = null;
			}
			if (vertUV2D != null)
			{
				vertUV2D[channel] = null;
			}
			if (vertUV4D != null)
			{
				vertUV4D[channel] = null;
			}
		}

		public void SetUVs(int channel, IList<Vector4> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvs != null && uvs.Count > 0)
			{
				if (vertUV4D == null)
				{
					vertUV4D = new UVChannels<Vector4>();
				}
				int count = uvs.Count;
				ResizableArray<Vector4> resizableArray = vertUV4D[channel];
				if (resizableArray != null)
				{
					resizableArray.Resize(count);
				}
				else
				{
					resizableArray = new ResizableArray<Vector4>(count, count);
					vertUV4D[channel] = resizableArray;
				}
				Vector4[] data = resizableArray.Data;
				uvs.CopyTo(data, 0);
			}
			else if (vertUV4D != null)
			{
				vertUV4D[channel] = null;
			}
			if (vertUV2D != null)
			{
				vertUV2D[channel] = null;
			}
			if (vertUV3D != null)
			{
				vertUV3D[channel] = null;
			}
		}

		public void SetUVs(int channel, IList<Vector4> uvs, int uvComponentCount)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			if (uvComponentCount < 0 || uvComponentCount > 4)
			{
				throw new ArgumentOutOfRangeException("uvComponentCount");
			}
			if (uvs != null && uvs.Count > 0 && uvComponentCount > 0)
			{
				if (uvComponentCount <= 2)
				{
					Vector2[] uvs2 = MeshUtils.ConvertUVsTo2D(uvs);
					SetUVs(channel, uvs2);
				}
				else if (uvComponentCount == 3)
				{
					Vector3[] uvs3 = MeshUtils.ConvertUVsTo3D(uvs);
					SetUVs(channel, uvs3);
				}
				else
				{
					SetUVs(channel, uvs);
				}
				return;
			}
			if (vertUV2D != null)
			{
				vertUV2D[channel] = null;
			}
			if (vertUV3D != null)
			{
				vertUV3D[channel] = null;
			}
			if (vertUV4D != null)
			{
				vertUV4D[channel] = null;
			}
		}

		public void SetUVsAuto(int channel, IList<Vector4> uvs)
		{
			if (channel < 0 || channel >= UVChannelCount)
			{
				throw new ArgumentOutOfRangeException("channel");
			}
			int usedUVComponents = MeshUtils.GetUsedUVComponents(uvs);
			SetUVs(channel, uvs, usedUVComponents);
		}

		public BlendShape[] GetAllBlendShapes()
		{
			if (blendShapes == null)
			{
				return null;
			}
			BlendShape[] array = new BlendShape[blendShapes.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = blendShapes[i].ToBlendShape();
			}
			return array;
		}

		public BlendShape GetBlendShape(int blendShapeIndex)
		{
			if (blendShapes == null || blendShapeIndex < 0 || blendShapeIndex >= blendShapes.Length)
			{
				throw new ArgumentOutOfRangeException("blendShapeIndex");
			}
			return blendShapes[blendShapeIndex].ToBlendShape();
		}

		public void ClearBlendShapes()
		{
			if (blendShapes != null)
			{
				blendShapes.Clear();
				blendShapes = null;
			}
		}

		public void AddBlendShape(BlendShape blendShape)
		{
			BlendShapeFrame[] frames = blendShape.Frames;
			if (frames == null || frames.Length == 0)
			{
				throw new ArgumentException("The frames cannot be null or empty.", "blendShape");
			}
			if (blendShapes == null)
			{
				blendShapes = new ResizableArray<BlendShapeContainer>(4, 0);
			}
			BlendShapeContainer item = new BlendShapeContainer(blendShape);
			blendShapes.Add(item);
		}

		public void AddBlendShapes(BlendShape[] blendShapes)
		{
			if (blendShapes == null)
			{
				throw new ArgumentNullException("blendShapes");
			}
			if (this.blendShapes == null)
			{
				this.blendShapes = new ResizableArray<BlendShapeContainer>(Math.Max(4, blendShapes.Length), 0);
			}
			for (int i = 0; i < blendShapes.Length; i++)
			{
				BlendShapeFrame[] frames = blendShapes[i].Frames;
				if (frames == null || frames.Length == 0)
				{
					throw new ArgumentException($"The frames of blend shape at index {i} cannot be null or empty.", "blendShapes");
				}
				BlendShapeContainer item = new BlendShapeContainer(blendShapes[i]);
				this.blendShapes.Add(item);
			}
		}

		public void Initialize(Mesh mesh)
		{
			if ((Object)(object)mesh == (Object)null)
			{
				throw new ArgumentNullException("mesh");
			}
			Vertices = mesh.vertices;
			Normals = mesh.normals;
			Tangents = mesh.tangents;
			Colors = mesh.colors;
			BoneWeights = mesh.boneWeights;
			bindposes = mesh.bindposes;
			for (int i = 0; i < UVChannelCount; i++)
			{
				if (simplificationOptions.ManualUVComponentCount)
				{
					switch (simplificationOptions.UVComponentCount)
					{
					case 1:
					case 2:
					{
						IList<Vector2> meshUVs2D = MeshUtils.GetMeshUVs2D(mesh, i);
						SetUVs(i, meshUVs2D);
						break;
					}
					case 3:
					{
						IList<Vector3> meshUVs3D = MeshUtils.GetMeshUVs3D(mesh, i);
						SetUVs(i, meshUVs3D);
						break;
					}
					case 4:
					{
						IList<Vector4> meshUVs = MeshUtils.GetMeshUVs(mesh, i);
						SetUVs(i, meshUVs);
						break;
					}
					}
				}
				else
				{
					IList<Vector4> meshUVs2 = MeshUtils.GetMeshUVs(mesh, i);
					SetUVsAuto(i, meshUVs2);
				}
			}
			BlendShape[] meshBlendShapes = MeshUtils.GetMeshBlendShapes(mesh);
			if (meshBlendShapes != null && meshBlendShapes.Length != 0)
			{
				AddBlendShapes(meshBlendShapes);
			}
			ClearSubMeshes();
			int num = mesh.subMeshCount;
			int[][] array = new int[num][];
			for (int j = 0; j < num; j++)
			{
				array[j] = mesh.GetTriangles(j);
			}
			AddSubMeshTriangles(array);
		}

		public void SimplifyMesh(float quality)
		{
			quality = Mathf.Clamp01(quality);
			int deletedTris = 0;
			ResizableArray<bool> deleted = new ResizableArray<bool>(20);
			ResizableArray<bool> deleted2 = new ResizableArray<bool>(20);
			Triangle[] data = triangles.Data;
			int length = triangles.Length;
			int num = length;
			_ = vertices.Data;
			int num2 = Mathf.RoundToInt((float)length * quality);
			for (int i = 0; i < simplificationOptions.MaxIterationCount; i++)
			{
				if (num - deletedTris <= num2)
				{
					break;
				}
				if (i % 5 == 0)
				{
					UpdateMesh(i);
					data = triangles.Data;
					length = triangles.Length;
					_ = vertices.Data;
				}
				for (int j = 0; j < length; j++)
				{
					data[j].dirty = false;
				}
				double num3 = 1E-09 * Math.Pow(i + 3, simplificationOptions.Agressiveness);
				if (verbose)
				{
					Debug.LogFormat("iteration {0} - triangles {1} threshold {2}", new object[3]
					{
						i,
						num - deletedTris,
						num3
					});
				}
				RemoveVertexPass(num, num2, num3, deleted, deleted2, ref deletedTris);
			}
			CompactMesh();
			if (verbose)
			{
				Debug.LogFormat("Finished simplification with triangle count {0}", new object[1] { triangles.Length });
			}
		}

		public void SimplifyMeshLossless()
		{
			int deletedTris = 0;
			ResizableArray<bool> deleted = new ResizableArray<bool>(0);
			ResizableArray<bool> deleted2 = new ResizableArray<bool>(0);
			Triangle[] data = triangles.Data;
			int length = triangles.Length;
			int startTrisCount = length;
			_ = vertices.Data;
			for (int i = 0; i < 9999; i++)
			{
				UpdateMesh(i);
				data = triangles.Data;
				length = triangles.Length;
				_ = vertices.Data;
				for (int j = 0; j < length; j++)
				{
					data[j].dirty = false;
				}
				double threshold = 0.001;
				if (verbose)
				{
					Debug.LogFormat("Lossless iteration {0} - triangles {1}", new object[2] { i, length });
				}
				RemoveVertexPass(startTrisCount, 0, threshold, deleted, deleted2, ref deletedTris);
				if (deletedTris <= 0)
				{
					break;
				}
				deletedTris = 0;
			}
			CompactMesh();
			if (verbose)
			{
				Debug.LogFormat("Finished simplification with triangle count {0}", new object[1] { triangles.Length });
			}
		}

		public Mesh ToMesh()
		{
			Vector3[] array = Vertices;
			Vector3[] normals = Normals;
			Vector4[] tangents = Tangents;
			Color[] colors = Colors;
			BoneWeight[] boneWeights = BoneWeights;
			int[][] allSubMeshTriangles = GetAllSubMeshTriangles();
			BlendShape[] allBlendShapes = GetAllBlendShapes();
			List<Vector2>[] array2 = null;
			List<Vector3>[] array3 = null;
			List<Vector4>[] array4 = null;
			if (vertUV2D != null)
			{
				array2 = new List<Vector2>[UVChannelCount];
				for (int i = 0; i < UVChannelCount; i++)
				{
					if (vertUV2D[i] != null)
					{
						List<Vector2> list = new List<Vector2>(array.Length);
						GetUVs(i, list);
						array2[i] = list;
					}
				}
			}
			if (vertUV3D != null)
			{
				array3 = new List<Vector3>[UVChannelCount];
				for (int j = 0; j < UVChannelCount; j++)
				{
					if (vertUV3D[j] != null)
					{
						List<Vector3> list2 = new List<Vector3>(array.Length);
						GetUVs(j, list2);
						array3[j] = list2;
					}
				}
			}
			if (vertUV4D != null)
			{
				array4 = new List<Vector4>[UVChannelCount];
				for (int k = 0; k < UVChannelCount; k++)
				{
					if (vertUV4D[k] != null)
					{
						List<Vector4> list3 = new List<Vector4>(array.Length);
						GetUVs(k, list3);
						array4[k] = list3;
					}
				}
			}
			return MeshUtils.CreateMesh(array, allSubMeshTriangles, normals, tangents, colors, boneWeights, array2, array3, array4, bindposes, allBlendShapes);
		}

		public static void ValidateOptions(SimplificationOptions options)
		{
			if (options.EnableSmartLink && options.VertexLinkDistance < 0.0)
			{
				throw new ValidateSimplificationOptionsException("VertexLinkDistance", "The vertex link distance cannot be negative when smart linking is enabled.");
			}
			if (options.MaxIterationCount <= 0)
			{
				throw new ValidateSi