using System;
using System.Collections.Generic;
using UnityEngine;

namespace SpriteViewer
{
	public class DynamicClothBone : MonoBehaviour
	{
		public static float InvSqrtFast(Vector3 f_vSrc)
		{
			float num = f_vSrc.x * f_vSrc.x + f_vSrc.y * f_vSrc.y + f_vSrc.z * f_vSrc.z;
			float num2 = 0.5f * num;
			int num3 = (int)num;
			num3 = 1597463174 - (num3 >> 1);
			num = (float)num3;
			num *= 1.5f - num2 * num * num;
			return 1f / num;
		}

		public Vertex[] vertices
		{
			get
			{
				return this._vertices;
			}
		}

		public Triangle[] triangles
		{
			get
			{
				return this._triangles;
			}
		}

		private void Start()
		{
			this._gridSize = this.gridSize * this.SimScale;
			int num = this._gridSize * this._gridSize;
			int num2 = (this._gridSize - 1) * this._gridSize * 2;
			num2 += (this._gridSize - 1) * (this._gridSize - 1) * 2;
			num2 += (this._gridSize - 2) * this._gridSize * 2;
			this._particles = new ClothParticle[num];
			this._springs = new ClothSpring[num2];
			this.InitMesh();
			this.UpdateParameters();
			this._Reset();
		}

		private void UpdateParameters()
		{
			this._gravity = this.Gravity * (float)this.SimScale;
			this._StretchStiffness = this.StretchStiffness * this.clothScale;
			this._BendStiffness = 1f * this.clothScale;
			this._mass = this.mass * (float)this.SimScale;
		}

		private void InitMesh()
		{
			int num = this._gridSize * this._gridSize * 2;
			this._triangles = new Triangle[num];
			int num2 = this._gridSize * this._gridSize;
			this._vertices = new Vertex[num2];
			int num3 = 0;
			for (int i = 0; i < this._gridSize - 1; i++)
			{
				for (int j = 0; j < this._gridSize - 1; j++)
				{
					int c = i * this._gridSize + j;
					int num4 = i * this._gridSize + j + 1;
					int a = (i + 1) * this._gridSize + j;
					int b = (i + 1) * this._gridSize + j + 1;
					this._triangles[num3].A = a;
					this._triangles[num3].B = num4;
					this._triangles[num3].C = c;
					num3++;
					this._triangles[num3].A = a;
					this._triangles[num3].B = b;
					this._triangles[num3].C = num4;
					num3++;
				}
			}
			for (int k = 0; k < this._gridSize; k++)
			{
				for (int l = 0; l < this._gridSize; l++)
				{
					int num5 = k * this._gridSize + l;
					this._vertices[num5].uv = new Vector2((float)l / (float)this._gridSize, (float)k / (float)this._gridSize);
				}
			}
		}

		public void _Reset()
		{
			for (int i = 0; i < this._gridSize; i++)
			{
				for (int j = 0; j < this._gridSize; j++)
				{
					float num = (float)j / (float)(this._gridSize - 1) - 0.5f;
					float num2 = (float)i / (float)(this._gridSize - 1) - 0.5f;
					int num3 = i * this._gridSize + j;
					this._particles[num3].currentPosition = new Vector3(this.clothScale * num, 8.5f, this.clothScale * num2);
					this._particles[num3].currentVelocity = Vector3.zero;
					this._particles[num3].defaultLocalPosition = this._particles[num3].currentPosition + base.transform.position;
					this._particles[num3].inverseMass = 1f / this._mass;
					this._particles[num3].pinned = false;
					this._particles[num3].tension = Vector3.zero;
				}
			}
			float magnitude = (this._particles[0].currentPosition - this._particles[1].currentPosition).magnitude;
			this._particles[0].pinned = true;
			this._particles[this._gridSize - 1].pinned = true;
			this._particles[this._gridSize * (this._gridSize - 1)].pinned = true;
			this._particles[this._gridSize * this._gridSize - 1].pinned = true;
			int num4 = 0;
			for (int k = 0; k < this._gridSize; k++)
			{
				for (int l = 0; l < this._gridSize - 1; l++)
				{
					this._springs[num4] = new ClothSpring(k * this._gridSize + l, k * this._gridSize + l + 1, magnitude, this._StretchStiffness);
					num4++;
				}
			}
			for (int m = 0; m < this._gridSize - 1; m++)
			{
				for (int n = 0; n < this._gridSize; n++)
				{
					this._springs[num4] = new ClothSpring(m * this._gridSize + n, (m + 1) * this._gridSize + n, magnitude, this._StretchStiffness);
					num4++;
				}
			}
			for (int num5 = 0; num5 < this._gridSize - 1; num5++)
			{
				for (int num6 = 0; num6 < this._gridSize - 1; num6++)
				{
					this._springs[num4] = new ClothSpring(num5 * this._gridSize + num6, (num5 + 1) * this._gridSize + num6 + 1, magnitude * (float)Math.Sqrt(2.0), this._BendStiffness);
					num4++;
				}
			}
			for (int num7 = 0; num7 < this._gridSize - 1; num7++)
			{
				for (int num8 = 1; num8 < this._gridSize; num8++)
				{
					this._springs[num4] = new ClothSpring(num7 * this._gridSize + num8, (num7 + 1) * this._gridSize + num8 - 1, magnitude * (float)Math.Sqrt(2.0), this._BendStiffness);
					num4++;
				}
			}
			for (int num9 = 0; num9 < this._gridSize; num9++)
			{
				for (int num10 = 0; num10 < this._gridSize - 2; num10++)
				{
					this._springs[num4] = new ClothSpring(num9 * this._gridSize + num10, num9 * this._gridSize + num10 + 2, magnitude * 2f, this._BendStiffness);
					num4++;
				}
			}
			for (int num11 = 0; num11 < this._gridSize - 2; num11++)
			{
				for (int num12 = 0; num12 < this._gridSize; num12++)
				{
					this._springs[num4] = new ClothSpring(num11 * this._gridSize + num12, (num11 + 2) * this._gridSize + num12, magnitude * 2f, this._BendStiffness);
					num4++;
				}
			}
			this.UpdateMesh();
		}

		private static Vector3 CalculateNormal(Vector3 VA, Vector3 VB, Vector3 VC)
		{
			Vector3 lhs = VB - VA;
			Vector3 rhs = VC - VA;
			Vector3 result = Vector3.Cross(lhs, rhs);
			result.Normalize();
			return result;
		}

		private void UpdateMesh()
		{
			for (int i = 0; i < this._triangles.Length; i++)
			{
				Triangle triangle = this._triangles[i];
				Vector3 position = this.vertices[triangle.A].position;
				Vector3 position2 = this.vertices[triangle.B].position;
				Vector3 position3 = this.vertices[triangle.C].position;
				this._triangles[i].normal = DynamicClothBone.CalculateNormal(position, position2, position3);
			}
			for (int j = 0; j < this._gridSize; j++)
			{
				for (int k = 0; k < this._gridSize; k++)
				{
					int num = j * this._gridSize + k;
					Vector3 vector = Vector3.zero;
					int num2 = 0;
					for (int l = 0; l <= 1; l++)
					{
						for (int m = 0; m <= 1; m++)
						{
							if (m + k < this._gridSize && l + j < this._gridSize)
							{
								int num3 = (j + l) * this._gridSize + (k + m) * 2;
								vector += this._triangles[num3].normal;
								num3++;
								vector += this._triangles[num3].normal;
								num2 += 2;
							}
						}
					}
					vector /= (float)num2;
					this._vertices[num].normal = vector;
				}
			}
			for (int n = 0; n < this._gridSize; n++)
			{
				for (int num4 = 0; num4 < this._gridSize; num4++)
				{
					int num5 = n * this._gridSize + num4;
					this._vertices[num5].position = this._particles[num5].currentPosition;
				}
			}
		}

		private void Update()
		{
			for (int i = 0; i < this._particles.Length; i++)
			{
				if (this._particles[i].pinned)
				{
					this._particles[i].currentPosition = base.transform.position + this._particles[i].defaultLocalPosition;
					this._particles[i].nextVelocity = Vector3.zero;
				}
			}
		}

		private void LateUpdate()
		{
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			if (unscaledDeltaTime <= 0f)
			{
				return;
			}
			this._timeSinceLastUpdate += unscaledDeltaTime;
			bool flag = false;
			float d = this.minimumPhysicsDelta;
			while (this._timeSinceLastUpdate > this.minimumPhysicsDelta)
			{
				this._timeSinceLastUpdate -= this.minimumPhysicsDelta;
				flag = true;
				for (int i = 0; i < this._springs.Length; i++)
				{
					Vector3 vector = this._particles[this._springs[i].P1].currentPosition - this._particles[this._springs[i].P2].currentPosition;
					float magnitude = vector.magnitude;
					float num = magnitude - this._springs[i]._NaturalLength;
					float num2 = this._springs[i]._Stiffness * (num * this._springs[i]._InverseLength);
					vector *= num2 / magnitude;
					ClothParticle[] particles = this._particles;
					int p = this._springs[i].P2;
					particles[p].tension = particles[p].tension + vector;
					ClothParticle[] particles2 = this._particles;
					int p2 = this._springs[i].P1;
					particles2[p2].tension = particles2[p2].tension - vector;
				}
				for (int j = 0; j < this._particles.Length; j++)
				{
					if (this._particles[j].pinned)
					{
						this._particles[j].nextPosition = this._particles[j].currentPosition;
						this._particles[j].nextVelocity = Vector3.zero;
					}
					else
					{
						Vector3 vector2 = this._gravity + this._particles[j].tension;
						Vector3 a = vector2 * this._particles[j].inverseMass;
						this._particles[j].nextVelocity = this._particles[j].currentVelocity + a * d;
						ClothParticle[] particles3 = this._particles;
						int num3 = j;
						particles3[num3].nextVelocity = particles3[num3].nextVelocity * this.dampFactor;
						vector2 = this._particles[j].nextVelocity * d;
						this._particles[j].nextPosition = this._particles[j].currentPosition + vector2;
						for (int k = 0; k < this._colliders.Count; k++)
						{
							Vector3 a2 = this._particles[j].nextPosition - this._colliders[k].Position;
							float num4 = this._colliders[k].Radius * 1.08f;
							if (a2.sqrMagnitude < num4 * num4)
							{
								a2.Normalize();
								a2 *= num4;
								this._particles[j].nextPosition = a2 + this._colliders[k].Position;
								this._particles[j].nextVelocity = Vector3.zero;
								break;
							}
						}
					}
				}
				for (int l = 0; l < this._particles.Length; l++)
				{
					this._particles[l].currentPosition = this._particles[l].nextPosition;
					this._particles[l].currentVelocity = this._particles[l].nextVelocity;
					this._particles[l].tension = Vector3.zero;
				}
			}
			if (flag)
			{
				this.UpdateMesh();
			}
		}

		public void AddCollider(Vector3 position, float radius)
		{
			ClothCollider item = new ClothCollider(position, radius);
			this._colliders.Add(item);
		}

		public void UnpinParticle(int index)
		{
			this._particles[index].pinned = false;
		}

		private void OnValidate()
		{
			if (Application.isPlaying && this._particles != null && this._springs != null && this._triangles != null)
			{
				this.UpdateParameters();
				this._Reset();
			}
		}

		private void OnDrawGizmosSelected()
		{
			if (this._particles != null)
			{
				for (int i = 0; i < this._particles.Length; i++)
				{
					Gizmos.DrawWireSphere(this._particles[i].currentPosition, 0.01f);
				}
			}
		}

		public int SimScale = 1;

		public float minimumPhysicsDelta = 0.01f;

		public float clothScale = 20f;

		public float StretchStiffness = 2.5f;

		private float _StretchStiffness;

		public float BendStiffness = 1f;

		private float _BendStiffness;

		public float mass = 0.01f;

		private float _mass;

		public float dampFactor = 0.9f;

		public int gridSize = 13;

		private int _gridSize;

		private ClothSpring[] _springs;

		private ClothParticle[] _particles;

		private float _timeSinceLastUpdate;

		public Vector3 Gravity = new Vector3(0f, -0.98f, 0f);

		private Vector3 _gravity;

		private List<ClothCollider> _colliders = new List<ClothCollider>();

		private Vertex[] _vertices;

		private Triangle[] _triangles;
	}
}
