public void Start () {
            if ( AstarPath.active == null ) throw new System.Exception ("There is no AstarPath object in the scene");

            graph = AstarPath.active.astarData.gridGraph;

            if ( graph == null ) throw new System.Exception ("The AstarPath object has no GridGraph");
            UpdateGraph ();
        }
		protected override void DrawMaxClimb (GridGraph graph) {
			var layerGridGraph = graph as LayerGridGraph;

			base.DrawMaxClimb(graph);
			layerGridGraph.maxClimb = Mathf.Clamp (layerGridGraph.maxClimb,0,layerGridGraph.characterHeight);

			if (layerGridGraph.maxClimb == layerGridGraph.characterHeight) {
				EditorGUILayout.HelpBox("Max climb needs to be smaller or equal to character height", MessageType.Info);
			}
		}
		protected override void DrawMiddleSection (GridGraph graph) {
			var layerGridGraph = graph as LayerGridGraph;

			DrawNeighbours(graph);

			layerGridGraph.characterHeight = EditorGUILayout.FloatField ("Character Height", layerGridGraph.characterHeight);
			DrawMaxClimb(graph);

			DrawMaxSlope(graph);
			DrawErosion(graph);

			layerGridGraph.mergeSpanRange = EditorGUILayout.FloatField ("Merge Span Range",layerGridGraph.mergeSpanRange);
		}
		void DrawFirstSection (GridGraph graph) {
			DrawWidthDepthFields (graph);

			newNodeSize = EditorGUILayout.FloatField (new GUIContent ("Node size","The size of a single node. The size is the side of the node square in world units"),graph.nodeSize);

			newNodeSize = newNodeSize <= 0.01F ? 0.01F : newNodeSize;

			float prevRatio = graph.aspectRatio;
			graph.aspectRatio = EditorGUILayout.FloatField (new GUIContent ("Aspect Ratio","Scaling of the nodes width/depth ratio. Good for isometric games"),graph.aspectRatio);

			DrawIsometricField(graph);

			if (graph.nodeSize != newNodeSize || prevRatio != graph.aspectRatio) {
				if (!locked) {
					graph.nodeSize = newNodeSize;
					Matrix4x4 oldMatrix = graph.matrix;
					graph.GenerateMatrix ();
					if (graph.matrix != oldMatrix) {
						//Rescann the graphs
						//AstarPath.active.AutoScan ();
						GUI.changed = true;
					}
				} else {
					int tmpWidth = graph.width;
					int tmpDepth = graph.depth;

					float delta = newNodeSize / graph.nodeSize;
					graph.nodeSize = newNodeSize;
					graph.unclampedSize = RoundVector3 (new Vector2 (tmpWidth*graph.nodeSize,tmpDepth*graph.nodeSize));
					Vector3 newCenter = graph.matrix.MultiplyPoint3x4 (new Vector3 ((tmpWidth/2F)*delta,0,(tmpDepth/2F)*delta));
					graph.center = RoundVector3 (newCenter);

					graph.GenerateMatrix ();

					//Make sure the width & depths stay the same
					graph.width = tmpWidth;
					graph.depth = tmpDepth;
					AutoScan ();
				}
			}

			DrawPositionField(graph);

			graph.rotation = EditorGUILayout.Vector3Field ("Rotation", graph.rotation);

			if (GUILayout.Button (new GUIContent ("Snap Size","Snap the size to exactly fit nodes"), GUILayout.MaxWidth (100), GUILayout.MaxHeight (16))) {
				SnapSizeToNodes (graph.width,graph.depth,graph);
			}
		}
		protected void DrawErosion (GridGraph graph) {
			graph.erodeIterations = EditorGUILayout.IntField (new GUIContent ("Erosion iterations","Sets how many times the graph should be eroded. This adds extra margin to objects."),graph.erodeIterations);
			graph.erodeIterations = graph.erodeIterations < 0 ? 0 : (graph.erodeIterations > 16 ? 16 : graph.erodeIterations); //Clamp iterations to [0,16]

			if ( graph.erodeIterations > 0 ) {
				EditorGUI.indentLevel++;
				graph.erosionUseTags = EditorGUILayout.Toggle (new GUIContent ("Erosion Uses Tags","Instead of making nodes unwalkable, " +
				"nodes will have their tag set to a value corresponding to their erosion level, " +
				"which is a quite good measurement of their distance to the closest wall.\nSee online documentation for more info."),
			                                               graph.erosionUseTags);
				if (graph.erosionUseTags) {
					EditorGUI.indentLevel++;
					graph.erosionFirstTag = EditorGUILayoutx.TagField ("First Tag",graph.erosionFirstTag);
					EditorGUI.indentLevel--;
				}
				EditorGUI.indentLevel--;
			}
		}
		protected void DrawMaxSlope (GridGraph graph) {
			graph.maxSlope = EditorGUILayout.Slider (new GUIContent ("Max Slope","Sets the max slope in degrees for a point to be walkable. Only enabled if Height Testing is enabled."),graph.maxSlope,0,90F);
		}
		protected virtual void DrawMaxClimb (GridGraph graph) {
			graph.maxClimb = EditorGUILayout.FloatField (new GUIContent ("Max Climb","How high in world units, relative to the graph, should a climbable level be. A zero (0) indicates infinity"),graph.maxClimb);
			if ( graph.maxClimb < 0 ) graph.maxClimb = 0;
			EditorGUI.indentLevel++;
			graph.maxClimbAxis = EditorGUILayout.IntPopup (new GUIContent ("Climb Axis","Determines which axis the above setting should test on"),graph.maxClimbAxis,new [] {new GUIContent ("X"),new GUIContent ("Y"),new GUIContent ("Z")},new [] {0,1,2});
			EditorGUI.indentLevel--;

			if ( graph.maxClimb > 0 && Mathf.Abs((Quaternion.Euler (graph.rotation) * new Vector3 (graph.nodeSize,0,graph.nodeSize))[graph.maxClimbAxis]) > graph.maxClimb ) {
				EditorGUILayout.HelpBox ("Nodes are spaced further apart than this in the grid. You might want to increase this value or change the axis", MessageType.Warning );
			}
		}
		/** Draws settings for using a texture as source for a grid.
		 * \astarpro
		 */
		protected virtual void DrawTextureData (GridGraph.TextureData data, GridGraph graph) {
			if (data == null) {
				return;
			}

			data.enabled = ToggleGroup ("Use Texture",data.enabled);
			if (!data.enabled) {
				return;
			}

			bool preGUI = GUI.enabled;
			GUI.enabled = data.enabled && GUI.enabled;

			EditorGUI.indentLevel++;
			data.source = ObjectField ("Source",data.source,typeof(Texture2D),false) as Texture2D;

			if (data.source != null) {
				string path = AssetDatabase.GetAssetPath (data.source);

				if (path != "") {
					var importer = AssetImporter.GetAtPath (path) as TextureImporter;
					if (!importer.isReadable) {
						if (FixLabel ("Texture is not readable")) {
							importer.isReadable = true;
							EditorUtility.SetDirty (importer);
							AssetDatabase.ImportAsset (path);
						}
					}
				}
			}

			for (int i=0;i<3;i++) {
				string channelName = i == 0 ? "R" : (i == 1 ? "G" : "B");
				data.channels[i] = (GridGraph.TextureData.ChannelUse)EditorGUILayout.Popup (channelName, (int)data.channels[i], ChannelUseNames);

				if (data.channels[i] != GridGraph.TextureData.ChannelUse.None) {
					EditorGUI.indentLevel++;
					data.factors[i] = EditorGUILayout.FloatField ("Factor",data.factors[i]);

					string help = "";
					switch (data.channels[i]) {
					case GridGraph.TextureData.ChannelUse.Penalty:
						help = "Nodes are applied penalty according to channel '"+channelName+"', multiplied with factor";
						break;
					case GridGraph.TextureData.ChannelUse.Position:
						help = "Nodes Y position is changed according to channel '"+channelName+"', multiplied with factor";

						if (graph.collision.heightCheck) {
							HelpBox ("Getting position both from raycast and from texture. You should disable one of them");
						}
						break;
					case GridGraph.TextureData.ChannelUse.WalkablePenalty:
						help = "If channel '"+channelName+"' is 0, the node is made unwalkable. Otherwise the node is applied penalty multiplied with factor";
						break;
					}

					HelpBox (help);

					EditorGUI.indentLevel--;
				}

			}

			if (GUILayout.Button ("Generate Reference")) {
				SaveReferenceTexture (graph);
			}

			GUI.enabled = preGUI;
			EditorGUI.indentLevel--;
		}
		protected virtual void DrawJPS (GridGraph graph) {
			graph.useJumpPointSearch = EditorGUILayout.Toggle (new GUIContent ("Use Jump Point Search", "Jump Point Search can significantly speed up pathfinding. But only works on uniformly weighted graphs"),graph.useJumpPointSearch);
			if ( graph.useJumpPointSearch ) {
				EditorGUILayout.HelpBox ("Jump Point Search assumes that there are no penalties applied to the graph. Tag penalties cannot be used either.", MessageType.Warning);

#if !ASTAR_JPS
				EditorGUILayout.HelpBox ("JPS needs to be enabled using a compiler directive before it can be used.\n" +
					"Enabling this will add ASTAR_JPS to the Scriping Define Symbols field in the Unity Player Settings", MessageType.Warning);
				if ( GUILayout.Button ("Enable Jump Point Search support") ) {
					OptimizationHandler.EnableDefine ("ASTAR_JPS");
				}
#endif
			} else {
#if ASTAR_JPS
				EditorGUILayout.HelpBox ("If you are not using JPS in any scene, you can disable it to save memory", MessageType.Info);
				if ( GUILayout.Button ("Disable Jump Point Search support") ) {
					OptimizationHandler.DisableDefine ("ASTAR_JPS");
				}
#endif
			}

		}
		void DrawIsometricField (GridGraph graph) {

			var isometricGUIContent = new GUIContent ("Isometric Angle", "For an isometric 2D game, you can use this parameter to scale the graph correctly.\nIt can also be used to create a hexagon grid.");
			var isometricOptions = new [] {new GUIContent ("None (0°)"), new GUIContent ("Isometric (≈54.74°)"), new GUIContent("Custom")};
			var isometricValues = new [] {0f, standardIsometric};
			var isometricOption = 2;

			for (int i = 0; i < isometricValues.Length; i++) {
				if (Mathf.Approximately (graph.isometricAngle, isometricValues[i])) {
					isometricOption = i;
				}
			}

			var prevIsometricOption = isometricOption;
			isometricOption = EditorGUILayout.IntPopup (isometricGUIContent, isometricOption, isometricOptions, new [] {0, 1, 2});
			if (prevIsometricOption != isometricOption) {
				// Change to something that will not match the predefined values above
				graph.isometricAngle = 45;
			}

			if (isometricOption < 2) {
				graph.isometricAngle = isometricValues[isometricOption];
			} else {
				// Custom
				graph.isometricAngle = EditorGUILayout.FloatField (isometricGUIContent, graph.isometricAngle);
			}
		}
		void DrawWidthDepthFields (GridGraph graph) {
			lockStyle = lockStyle ?? AstarPathEditor.astarSkin.FindStyle ("GridSizeLock") ?? new GUIStyle ();

			GUILayout.BeginHorizontal ();
			GUILayout.BeginVertical ();
			int newWidth = EditorGUILayout.IntField (new GUIContent ("Width (nodes)","Width of the graph in nodes"), graph.width);
			int newDepth = EditorGUILayout.IntField (new GUIContent ("Depth (nodes)","Depth (or height you might also call it) of the graph in nodes"), graph.depth);
			GUILayout.EndVertical ();

			Rect lockRect = GUILayoutUtility.GetRect (lockStyle.fixedWidth,lockStyle.fixedHeight);

			GUILayout.EndHorizontal ();

			// All the layouts mess up the margin to the next control, so add it manually
			GUILayout.Space (2);

			// Add a small offset to make it better centred around the controls
			lockRect.y += 3;
			lockRect.width = lockStyle.fixedWidth;
			lockRect.height = lockStyle.fixedHeight;
			lockRect.x += lockStyle.margin.left;
			lockRect.y += lockStyle.margin.top;

			locked = GUI.Toggle (lockRect,locked,
			                     new GUIContent ("", "If the width and depth values are locked, " +
			                "changing the node size will scale the grid which keeping the number of nodes consistent " +
			                "instead of keeping the size the same and changing the number of nodes in the graph"), lockStyle);

			if (newWidth != graph.width || newDepth != graph.depth) {
				SnapSizeToNodes (newWidth,newDepth,graph);
			}
		}
		protected override void DrawCutCorners (GridGraph graph) {
			// No corner cutting since only 4 neighbours are possible
		}
		protected override void DrawNeighbours (GridGraph graph) {
			graph.neighbours = NumNeighbours.Four;
			EditorGUI.BeginDisabledGroup(true);
			EditorGUILayout.EnumPopup (new GUIContent ("Connections","Only 4 connections per node is possible on layered grid graphs"),graph.neighbours);
			EditorGUI.EndDisabledGroup();
		}
		protected override void DrawTextureData (GridGraph.TextureData data, GridGraph graph) {
			// No texture data for layered grid graphs
		}
		void DrawLastSection (GridGraph graph) {
			GUILayout.Label (new GUIContent ("Advanced"), EditorStyles.boldLabel);

			DrawPenaltyModifications (graph);
			DrawJPS (graph);
		}
		void DrawPenaltyModifications (GridGraph graph) {
			showExtra = EditorGUILayout.Foldout (showExtra, "Penalty Modifications");

			if (showExtra) {
				EditorGUI.indentLevel+=2;

				graph.penaltyAngle = ToggleGroup (new GUIContent ("Angle Penalty","Adds a penalty based on the slope of the node"),graph.penaltyAngle);
				if (graph.penaltyAngle) {
					EditorGUI.indentLevel++;
					graph.penaltyAngleFactor = EditorGUILayout.FloatField (new GUIContent ("Factor","Scale of the penalty. A negative value should not be used"),graph.penaltyAngleFactor);
					graph.penaltyAnglePower = EditorGUILayout.Slider ("Power", graph.penaltyAnglePower, 0.1f, 10f);
					HelpBox ("Applies penalty to nodes based on the angle of the hit surface during the Height Testing\nPenalty applied is: P=(1-cos(angle)^power)*factor.");

					EditorGUI.indentLevel--;
				}

				graph.penaltyPosition = ToggleGroup ("Position Penalty",graph.penaltyPosition);
				if (graph.penaltyPosition) {
					EditorGUI.indentLevel++;
					graph.penaltyPositionOffset = EditorGUILayout.FloatField ("Offset",graph.penaltyPositionOffset);
					graph.penaltyPositionFactor = EditorGUILayout.FloatField ("Factor",graph.penaltyPositionFactor);
					HelpBox ("Applies penalty to nodes based on their Y coordinate\nSampled in Int3 space, i.e it is multiplied with Int3.Precision first ("+Int3.Precision+")\n" +
						"Be very careful when using negative values since a negative penalty will underflow and instead get really high");
					EditorGUI.indentLevel--;
				}

				DrawTextureData (graph.textureData, graph);
				EditorGUI.indentLevel-=2;
			}
		}
		void DrawPositionField (GridGraph graph) {
			Vector3 pivotPoint;
			Vector3 diff;

			GUILayout.BeginHorizontal ();

			switch (pivot) {
				case GridPivot.Center:
					graph.center = RoundVector3 ( graph.center );
					graph.center = EditorGUILayout.Vector3Field ("Center",graph.center);
					break;
				case GridPivot.TopLeft:
					pivotPoint = graph.matrix.MultiplyPoint3x4 (new Vector3 (0,0,graph.depth));
					pivotPoint = RoundVector3 ( pivotPoint );
					diff = pivotPoint-graph.center;
					pivotPoint = EditorGUILayout.Vector3Field ("Top-Left",pivotPoint);
					graph.center = pivotPoint-diff;
					break;
				case GridPivot.TopRight:
					pivotPoint = graph.matrix.MultiplyPoint3x4 (new Vector3 (graph.width,0,graph.depth));
					pivotPoint = RoundVector3 ( pivotPoint );
					diff = pivotPoint-graph.center;
					pivotPoint = EditorGUILayout.Vector3Field ("Top-Right",pivotPoint);
					graph.center = pivotPoint-diff;
					break;
				case GridPivot.BottomLeft:
					pivotPoint = graph.matrix.MultiplyPoint3x4 (new Vector3 (0,0,0));
					pivotPoint = RoundVector3 ( pivotPoint );
					diff = pivotPoint-graph.center;
					pivotPoint = EditorGUILayout.Vector3Field ("Bottom-Left",pivotPoint);
					graph.center = pivotPoint-diff;
					break;
				case GridPivot.BottomRight:
					pivotPoint = graph.matrix.MultiplyPoint3x4 (new Vector3 (graph.width,0,0));
					pivotPoint = RoundVector3 ( pivotPoint );
					diff = pivotPoint-graph.center;
					pivotPoint = EditorGUILayout.Vector3Field ("Bottom-Right",pivotPoint);
					graph.center = pivotPoint-diff;
					break;
			}

			graph.GenerateMatrix ();

			pivot = PivotPointSelector (pivot);

			GUILayout.EndHorizontal ();
		}
		static void SaveReferenceTexture (GridGraph graph) {
			if (graph.nodes == null || graph.nodes.Length != graph.width * graph.depth) {
				AstarPath.active.Scan ();
			}

			if (graph.nodes.Length != graph.width * graph.depth) {
				Debug.LogError ("Couldn't create reference image since width*depth != nodes.Length");
				return;
			}

			if (graph.nodes.Length == 0) {
				Debug.LogError ("Couldn't create reference image since the graph is too small (0*0)");
				return;
			}

			var tex = new Texture2D (graph.width,graph.depth);

			float maxY = float.NegativeInfinity;
			for (int i=0;i<graph.nodes.Length;i++) {
				Vector3 p = graph.inverseMatrix.MultiplyPoint ((Vector3)graph.nodes[i].position);
				maxY = p.y > maxY ? p.y : maxY;
			}

			var cols = new Color[graph.width*graph.depth];

			for (int z=0;z<graph.depth;z++) {
				for (int x=0;x<graph.width;x++) {
					GraphNode node = graph.nodes[z*graph.width+x];
					float v = node.Walkable ? 1F : 0.0F;
					Vector3 p = graph.inverseMatrix.MultiplyPoint ((Vector3)node.position);
					float q = p.y / maxY;
					cols[z*graph.width+x] = new Color (v,q,0);
				}
			}
			tex.SetPixels (cols);
			tex.Apply ();

			string path = AssetDatabase.GenerateUniqueAssetPath ("Assets/gridReference.png");

			using (var outstream = new System.IO.StreamWriter (path)) {
				using (var outfile = new System.IO.BinaryWriter (outstream.BaseStream)) {
					outfile.Write (tex.EncodeToPNG ());
				}
			}
			AssetDatabase.Refresh ();
			Object obj = AssetDatabase.LoadAssetAtPath (path,typeof (Texture));

			EditorGUIUtility.PingObject (obj);
		}
		protected virtual void DrawMiddleSection (GridGraph graph) {
			DrawNeighbours(graph);
			DrawMaxClimb(graph);
			DrawMaxSlope(graph);
			DrawErosion(graph);
		}
		public void SnapSizeToNodes (int newWidth, int newDepth, GridGraph graph) {
			graph.unclampedSize = new Vector2 (newWidth*graph.nodeSize,newDepth*graph.nodeSize);
			Vector3 newCenter = graph.matrix.MultiplyPoint3x4 (new Vector3 (newWidth/2F,0,newDepth/2F));
			graph.center = newCenter;
			graph.GenerateMatrix ();
			AutoScan ();

			GUI.changed = true;
		}
		protected virtual void DrawCutCorners (GridGraph graph) {
			graph.cutCorners = EditorGUILayout.Toggle (new GUIContent ("Cut Corners","Enables or disables cutting corners. See docs for image example"),graph.cutCorners);
			if ( !graph.cutCorners && graph.useJumpPointSearch ) {
				EditorGUILayout.HelpBox ("Jump Point Search only works if 'Cut Corners' is enabled.", MessageType.Error);
			}
		}
		protected virtual void DrawNeighbours (GridGraph graph) {
			graph.neighbours = (NumNeighbours)EditorGUILayout.EnumPopup (new GUIContent ("Connections","Sets how many connections a node should have to it's neighbour nodes."),graph.neighbours);

			EditorGUI.indentLevel++;

			if (graph.neighbours == NumNeighbours.Eight) {
				DrawCutCorners(graph);
			}

			if (graph.neighbours == NumNeighbours.Six) {
				graph.uniformEdgeCosts = EditorGUILayout.Toggle (new GUIContent ("Hexagon connection costs", "Tweak the edge costs in the graph to be more suitable for hexagon graphs"), graph.uniformEdgeCosts);
				if ((!Mathf.Approximately(graph.isometricAngle, standardIsometric) || !graph.uniformEdgeCosts) && GUILayout.Button ("Configure as hexagon graph")) {
					graph.isometricAngle = standardIsometric;
					graph.uniformEdgeCosts = true;
				}
			} else {
				graph.uniformEdgeCosts = false;
			}

			EditorGUI.indentLevel--;

			if ( graph.neighbours != NumNeighbours.Eight && graph.useJumpPointSearch ) {
				EditorGUILayout.HelpBox ("Jump Point Search only works for 8 neighbours.", MessageType.Error);
			}
		}
		protected override void DrawJPS (GridGraph graph) {
			// No JPS for layered grid graph
		}