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

namespace Leap.Unity.RuntimeGizmos
{
	public class RuntimeGizmoDrawer
	{
		public Shader gizmoShader
		{
			get
			{
				if (this._gizmoMaterial == null)
				{
					return null;
				}
				return this._gizmoMaterial.shader;
			}
			set
			{
				if (this._gizmoMaterial == null)
				{
					this._gizmoMaterial = new Material(value);
					this._gizmoMaterial.name = "Runtime Gizmo Material";
					this._gizmoMaterial.hideFlags = HideFlags.HideAndDontSave;
				}
				else
				{
					this._gizmoMaterial.shader = value;
				}
			}
		}

		public void BeginGuard()
		{
			this._operationCountOnGuard = this._operations.Count;
		}

		public void EndGuard()
		{
			bool flag = this._operations.Count > this._operationCountOnGuard;
			this._operationCountOnGuard = -1;
			if (flag)
			{
				Debug.LogError("New gizmos were drawn to the front buffer!  Make sure to never keep a reference to a Drawer, always get a new one every time you want to start drawing.");
			}
		}

		public void RelativeTo(Transform transform)
		{
			this.matrix = transform.localToWorldMatrix;
		}

		public void PushMatrix()
		{
			this._matrixStack.Push(this._currMatrix);
		}

		public void PopMatrix()
		{
			this.matrix = this._matrixStack.Pop();
		}

		public void ResetMatrixAndColorState()
		{
			this.matrix = Matrix4x4.identity;
			this.color = Color.white;
		}

		public Color color
		{
			get
			{
				return this._currColor;
			}
			set
			{
				if (this._currColor == value)
				{
					return;
				}
				this._currColor = value;
				this._operations.Add(RuntimeGizmoDrawer.OperationType.SetColor);
				this._colors.Add(this._currColor);
			}
		}

		public Matrix4x4 matrix
		{
			get
			{
				return this._currMatrix;
			}
			set
			{
				if (this._currMatrix == value)
				{
					return;
				}
				this._currMatrix = value;
				this._operations.Add(RuntimeGizmoDrawer.OperationType.SetMatrix);
				this._matrices.Add(this._currMatrix);
			}
		}

		public void DrawMesh(Mesh mesh, Matrix4x4 matrix)
		{
			this.setWireMode(false);
			this.drawMeshInternal(mesh, matrix);
		}

		public void DrawMesh(Mesh mesh, Vector3 position, Quaternion rotation, Vector3 scale)
		{
			this.DrawMesh(mesh, Matrix4x4.TRS(position, rotation, scale));
		}

		public void DrawWireMesh(Mesh mesh, Matrix4x4 matrix)
		{
			this.setWireMode(true);
			this.drawMeshInternal(mesh, matrix);
		}

		public void DrawWireMesh(Mesh mesh, Vector3 position, Quaternion rotation, Vector3 scale)
		{
			this.DrawWireMesh(mesh, Matrix4x4.TRS(position, rotation, scale));
		}

		public void DrawLine(Vector3 a, Vector3 b)
		{
			this._operations.Add(RuntimeGizmoDrawer.OperationType.DrawLine);
			this._lines.Add(new RuntimeGizmoDrawer.Line(a, b));
		}

		public void DrawCube(Vector3 position, Vector3 size)
		{
			this.DrawMesh(this.cubeMesh, position, Quaternion.identity, size);
		}

		public void DrawWireCube(Vector3 position, Vector3 size)
		{
			this.DrawWireMesh(this.wireCubeMesh, position, Quaternion.identity, size);
		}

		public void DrawSphere(Vector3 center, float radius)
		{
			this.DrawMesh(this.sphereMesh, center, Quaternion.identity, Vector3.one * radius * 2f);
		}

		public void DrawWireSphere(Vector3 center, float radius)
		{
			this.DrawWireMesh(this.wireSphereMesh, center, Quaternion.identity, Vector3.one * radius * 2f);
		}

		public void DrawWireCirlce(Vector3 center, Vector3 direction, float radius)
		{
			this.PushMatrix();
			this.matrix = Matrix4x4.TRS(center, Quaternion.LookRotation(direction), new Vector3(1f, 1f, 0f)) * this.matrix;
			this.DrawWireSphere(Vector3.zero, radius);
			this.PopMatrix();
		}

		public void DrawColliders(GameObject gameObject, bool useWireframe = true, bool traverseHierarchy = true)
		{
			this.PushMatrix();
			if (traverseHierarchy)
			{
				gameObject.GetComponentsInChildren<Collider>(this._colliderList);
			}
			else
			{
				gameObject.GetComponents<Collider>(this._colliderList);
			}
			for (int i = 0; i < this._colliderList.Count; i++)
			{
				Collider collider = this._colliderList[i];
				this.RelativeTo(collider.transform);
				if (collider is BoxCollider)
				{
					BoxCollider boxCollider = collider as BoxCollider;
					if (useWireframe)
					{
						this.DrawWireCube(boxCollider.center, boxCollider.size);
					}
					else
					{
						this.DrawCube(boxCollider.center, boxCollider.size);
					}
				}
				else if (collider is SphereCollider)
				{
					SphereCollider sphereCollider = collider as SphereCollider;
					if (useWireframe)
					{
						this.DrawWireSphere(sphereCollider.center, sphereCollider.radius);
					}
					else
					{
						this.DrawSphere(sphereCollider.center, sphereCollider.radius);
					}
				}
				else if (collider is CapsuleCollider)
				{
					CapsuleCollider capsuleCollider = collider as CapsuleCollider;
					Vector3 vector = Vector3.zero;
					vector += Vector3.one * capsuleCollider.radius * 2f;
					vector += new Vector3((float)((capsuleCollider.direction != 0) ? 0 : 1), (float)((capsuleCollider.direction != 1) ? 0 : 1), (float)((capsuleCollider.direction != 2) ? 0 : 1)) * (capsuleCollider.height - capsuleCollider.radius * 2f);
					if (useWireframe)
					{
						this.DrawWireCube(capsuleCollider.center, vector);
					}
					else
					{
						this.DrawCube(capsuleCollider.center, vector);
					}
				}
				else if (collider is MeshCollider)
				{
					MeshCollider meshCollider = collider as MeshCollider;
					if (meshCollider.sharedMesh != null)
					{
						if (useWireframe)
						{
							this.DrawWireMesh(meshCollider.sharedMesh, Matrix4x4.identity);
						}
						else
						{
							this.DrawMesh(meshCollider.sharedMesh, Matrix4x4.identity);
						}
					}
				}
			}
			this.PopMatrix();
		}

		public void ClearAllGizmos()
		{
			this._operations.Clear();
			this._matrices.Clear();
			this._colors.Clear();
			this._lines.Clear();
			this._meshes.Clear();
			this._isInWireMode = false;
			this._currMatrix = Matrix4x4.identity;
			this._currColor = Color.white;
		}

		public void DrawAllGizmosToScreen()
		{
			try
			{
				int num = 0;
				int num2 = 0;
				int num3 = 0;
				int num4 = 0;
				int num5 = -1;
				this._currMatrix = Matrix4x4.identity;
				this._currColor = Color.white;
				GL.wireframe = false;
				for (int i = 0; i < this._operations.Count; i++)
				{
					RuntimeGizmoDrawer.OperationType operationType = this._operations[i];
					switch (operationType)
					{
					case RuntimeGizmoDrawer.OperationType.SetMatrix:
						this._currMatrix = this._matrices[num++];
						break;
					case RuntimeGizmoDrawer.OperationType.ToggleWireframe:
						GL.wireframe = !GL.wireframe;
						break;
					case RuntimeGizmoDrawer.OperationType.SetColor:
						this._currColor = this._colors[num2++];
						num5 = -1;
						break;
					case RuntimeGizmoDrawer.OperationType.DrawLine:
					{
						this.setPass(ref num5, true);
						GL.Begin(1);
						RuntimeGizmoDrawer.Line line = this._lines[num3++];
						GL.Vertex(this._currMatrix.MultiplyPoint(line.a));
						GL.Vertex(this._currMatrix.MultiplyPoint(line.b));
						GL.End();
						break;
					}
					case RuntimeGizmoDrawer.OperationType.DrawMesh:
						if (GL.wireframe)
						{
							this.setPass(ref num5, true);
						}
						else
						{
							this.setPass(ref num5, false);
						}
						Graphics.DrawMeshNow(this._meshes[num4++], this._currMatrix * this._matrices[num++]);
						break;
					default:
						throw new InvalidOperationException("Unexpected operation type " + operationType);
					}
				}
			}
			finally
			{
				GL.wireframe = false;
			}
		}

		private void setPass(ref int currPass, bool isUnlit)
		{
			int num;
			if (isUnlit)
			{
				if (this._currColor.a < 1f)
				{
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else if (this._currColor.a < 1f)
			{
				num = 3;
			}
			else
			{
				num = 2;
			}
			if (currPass != num)
			{
				currPass = num;
				this._gizmoMaterial.color = this._currColor;
				this._gizmoMaterial.SetPass(currPass);
			}
		}

		private void drawMeshInternal(Mesh mesh, Matrix4x4 matrix)
		{
			if (mesh == null)
			{
				throw new InvalidOperationException("Mesh cannot be null!");
			}
			this._operations.Add(RuntimeGizmoDrawer.OperationType.DrawMesh);
			this._meshes.Add(mesh);
			this._matrices.Add(matrix);
		}

		private void setWireMode(bool wireMode)
		{
			if (this._isInWireMode != wireMode)
			{
				this._operations.Add(RuntimeGizmoDrawer.OperationType.ToggleWireframe);
				this._isInWireMode = wireMode;
			}
		}

		public const int UNLIT_SOLID_PASS = 0;

		public const int UNLIT_TRANSPARENT_PASS = 1;

		public const int SHADED_SOLID_PASS = 2;

		public const int SHADED_TRANSPARENT_PASS = 3;

		private List<RuntimeGizmoDrawer.OperationType> _operations = new List<RuntimeGizmoDrawer.OperationType>();

		private List<Matrix4x4> _matrices = new List<Matrix4x4>();

		private List<Color> _colors = new List<Color>();

		private List<RuntimeGizmoDrawer.Line> _lines = new List<RuntimeGizmoDrawer.Line>();

		private List<Mesh> _meshes = new List<Mesh>();

		private Color _currColor = Color.white;

		private Matrix4x4 _currMatrix = Matrix4x4.identity;

		private Stack<Matrix4x4> _matrixStack = new Stack<Matrix4x4>();

		private bool _isInWireMode;

		private Material _gizmoMaterial;

		private int _operationCountOnGuard = -1;

		public Mesh cubeMesh;

		public Mesh wireCubeMesh;

		public Mesh sphereMesh;

		public Mesh wireSphereMesh;

		private List<Collider> _colliderList = new List<Collider>();

		private enum OperationType
		{
			SetMatrix,
			ToggleWireframe,
			SetColor,
			DrawLine,
			DrawMesh
		}

		private struct Line
		{
			public Line(Vector3 a, Vector3 b)
			{
				this.a = a;
				this.b = b;
			}

			public Vector3 a;

			public Vector3 b;
		}
	}
}
