////////////////////////////////////////////////////////////////////////////////////////////////
		/*--------------------------------------------------------------------------------------------*/
		protected override void UpdateMesh(MeshType pType, MeshBuilder pMeshBuild, float pAmount=1) {
			if ( pType == MeshType.Edge ) {
				MeshUtil.BuildBorderMesh(pMeshBuild, vMeshW, vMeshH, EdgeThick);
				pMeshBuild.Commit();
				return;
			}

			float inset = (pType != MeshType.Background ? EdgeThick*2 : 0);

			MeshUtil.BuildRectangleMesh(pMeshBuild, Math.Max(0, vMeshW-inset), 
				Math.Max(0, vMeshH-inset), pAmount);
			pMeshBuild.Commit();
		}
		////////////////////////////////////////////////////////////////////////////////////////////////
		/*--------------------------------------------------------------------------------------------*/
		public virtual void Build(MenuState pMenuState, IItemVisualSettings pSettings, 
																		float pAngle0, float pAngle1) {
			vMenuState = pMenuState;
			vSettings = (ItemVisualSettingsStandard)pSettings;
			vAngle0 = pAngle0;
			vAngle1 = pAngle1;
			vMeshSteps = (int)Math.Round(Math.Max(2, (vAngle1-vAngle0)/Math.PI*60));

			////

			vBackground = new GameObject("Background");
			vBackground.transform.SetParent(gameObject.transform, false);
			vBackground.AddComponent<MeshRenderer>();
			
			MeshFilter bgFilt = vBackground.AddComponent<MeshFilter>();
			vBackgroundMeshBuilder = new MeshBuilder();
			BuildMesh(vBackgroundMeshBuilder);
			vBackgroundMeshBuilder.Commit();
			vBackgroundMeshBuilder.CommitColors(Color.clear);
			bgFilt.sharedMesh = vBackgroundMeshBuilder.Mesh;

			////

			var labelObj = new GameObject("Label");
			labelObj.transform.SetParent(gameObject.transform, false);
			labelObj.transform.localPosition = new Vector3(0, 0, InnerRadius);
			labelObj.transform.localRotation = Quaternion.FromToRotation(Vector3.back, Vector3.right);
			labelObj.transform.localScale = new Vector3((vMenuState.IsOnLeftSide ? 1 : -1), 1, 1);

			vLabel = labelObj.AddComponent<UiLabel>();
			vLabel.AlignLeft = vMenuState.IsOnLeftSide;
		}
		////////////////////////////////////////////////////////////////////////////////////////////////
		/*--------------------------------------------------------------------------------------------*/
		public override void Build(IHovercastMenuState pMenuState, IBaseItemState pItemState,
													float pArcAngle, IItemVisualSettings pSettings) {
			base.Build(pMenuState, pItemState, pArcAngle, pSettings);

			////

			vOuter = new GameObject("ToggleOuter");
			vOuter.transform.SetParent(gameObject.transform, false);
			vOuter.transform.localRotation = vLabel.CanvasLocalRotation;
			vOuter.AddComponent<MeshRenderer>();

			MeshFilter outerFilt = vOuter.AddComponent<MeshFilter>();
			vOuterMeshBuilder = new MeshBuilder();
			MeshUtil.BuildQuadMesh(vOuterMeshBuilder);
			Materials.SetMeshIconCoords(vOuterMeshBuilder, GetOuterIconOffset());
			vOuterMeshBuilder.Commit();
			vOuterMeshBuilder.CommitColors(Color.clear);
			outerFilt.sharedMesh = vOuterMeshBuilder.Mesh;

			////

			vInner = new GameObject("ToggleInner");
			vInner.transform.SetParent(gameObject.transform, false);
			vInner.transform.localRotation = vLabel.CanvasLocalRotation;
			vInner.AddComponent<MeshRenderer>();

			MeshFilter innerFilt = vInner.AddComponent<MeshFilter>();
			vInnerMeshBuilder = new MeshBuilder();
			MeshUtil.BuildQuadMesh(vInnerMeshBuilder);
			Materials.SetMeshIconCoords(vInnerMeshBuilder, GetInnerIconOffset());
			vInnerMeshBuilder.Commit();
			vInnerMeshBuilder.CommitColors(Color.clear);
			innerFilt.sharedMesh = vInnerMeshBuilder.Mesh;
		}
		////////////////////////////////////////////////////////////////////////////////////////////////
		/*--------------------------------------------------------------------------------------------*/
		public virtual void Build(IHovercastMenuState pMenuState, IBaseItemState pItemState,
													float pArcAngle, IItemVisualSettings pSettings) {
			vMenuState = pMenuState;
			vItemState = pItemState;
			vSelItem = (vItemState.Item as ISelectableItem);
			vSettings = (ItemVisualSettingsStandard)pSettings;

			////

			vHoverSlice = new UiHoverMeshSlice(gameObject);
			vHoverSlice.DrawOuterEdge = true;
			vHoverSlice.UpdateSize(InnerRadius, OuterRadius, pArcAngle);

			////
			
			vIcon = new GameObject("Icon");
			vIcon.transform.SetParent(gameObject.transform, false);
			vIcon.transform.localRotation = Quaternion.FromToRotation(Vector3.forward, Vector3.up)*
				Quaternion.FromToRotation(Vector3.right, Vector3.up);
			vIcon.AddComponent<MeshRenderer>();

			MeshFilter iconFilt = vIcon.AddComponent<MeshFilter>();
			vIconMeshBuilder = new MeshBuilder();
			MeshUtil.BuildQuadMesh(vIconMeshBuilder);
			Materials.SetMeshIconCoords(vIconMeshBuilder, Materials.IconOffset.Parent);
			vIconMeshBuilder.Commit();
			vIconMeshBuilder.CommitColors(Color.clear);
			iconFilt.sharedMesh = vIconMeshBuilder.Mesh;
		}
		////////////////////////////////////////////////////////////////////////////////////////////////
		/*--------------------------------------------------------------------------------------------*/
		public virtual void Build(ProjectionState pProjectionState,
																IProjectionVisualSettings pSettings) {
			vProjectionState = pProjectionState;
			vSettings = (ProjectionVisualSettingsStandard)pSettings;

			////

			vSpotObj = new GameObject("Spot");
			vSpotObj.transform.SetParent(gameObject.transform, false);
			vSpotObj.transform.localScale = Vector3.zero;

			MeshFilter spotFilt = vSpotObj.AddComponent<MeshFilter>();
			vSpotMeshBuilder = new MeshBuilder(spotFilt.mesh);
			MeshUtil.BuildCircleMesh(vSpotMeshBuilder, 0.5f, 32);
			vSpotMeshBuilder.Commit();

			MeshRenderer spotRend = vSpotObj.AddComponent<MeshRenderer>();
			spotRend.sharedMaterial = 
				Materials.GetLayer(Materials.Layer.AboveText, Materials.DepthHintMax);

			////

			vLineObj = GameObject.CreatePrimitive(PrimitiveType.Cube);
			vLineObj.name = "Line";
			vLineObj.transform.SetParent(gameObject.transform, false);
			vLineObj.transform.localScale = Vector3.zero;

			vLineMeshBuilder = new MeshBuilder(vLineObj.GetComponent<MeshFilter>().mesh);

			MeshRenderer lineRend = vLineObj.GetComponent<MeshRenderer>();
			lineRend.sharedMaterial = 
				Materials.GetLayer(Materials.Layer.AboveText, Materials.DepthHintMax);
		}
		////////////////////////////////////////////////////////////////////////////////////////////////
		/*--------------------------------------------------------------------------------------------*/
		public override void Build(IHoverboardPanelState pPanelState,
										IHoverboardLayoutState pLayoutState, IBaseItemState pItemState,
										IItemVisualSettings pSettings) {
			base.Build(pPanelState, pLayoutState, pItemState, pSettings);

			vLabel.AlignLeft = true;
			vLabel.transform.localPosition = new Vector3(-vItemState.Item.Width/2, 0, 0);

			////

			vOuter = new GameObject("ToggleOuter");
			vOuter.transform.SetParent(gameObject.transform, false);
			vOuter.transform.localRotation = vLabel.CanvasLocalRotation;
			vOuter.AddComponent<MeshRenderer>();

			MeshFilter outerFilt = vOuter.AddComponent<MeshFilter>();
			vOuterMeshBuilder = new MeshBuilder();
			MeshUtil.BuildQuadMesh(vOuterMeshBuilder);
			Materials.SetMeshIconCoords(vOuterMeshBuilder, GetOuterIconOffset());
			vOuterMeshBuilder.Commit();
			vOuterMeshBuilder.CommitColors(Color.clear);
			outerFilt.sharedMesh = vOuterMeshBuilder.Mesh;

			////

			vInner = new GameObject("ToggleInner");
			vInner.transform.SetParent(gameObject.transform, false);
			vInner.transform.localRotation = vLabel.CanvasLocalRotation;
			vInner.AddComponent<MeshRenderer>();

			MeshFilter innerFilt = vInner.AddComponent<MeshFilter>();
			vInnerMeshBuilder = new MeshBuilder();
			MeshUtil.BuildQuadMesh(vInnerMeshBuilder);
			Materials.SetMeshIconCoords(vInnerMeshBuilder, GetInnerIconOffset());
			vInnerMeshBuilder.Commit();
			vInnerMeshBuilder.CommitColors(Color.clear);
			innerFilt.sharedMesh = vInnerMeshBuilder.Mesh;
		}
		////////////////////////////////////////////////////////////////////////////////////////////////
		/*--------------------------------------------------------------------------------------------*/
		public override void Build(IHoverboardPanelState pPanelState,
										IHoverboardLayoutState pLayoutState, IBaseItemState pItemState,
										IItemVisualSettings pSettings) {
			base.Build(pPanelState, pLayoutState, pItemState, pSettings);

			vLabel.AlignLeft = true;

			////

			vIcon = new GameObject("Icon");
			vIcon.transform.SetParent(gameObject.transform, false);
			vIcon.transform.localRotation = 
				vLabel.gameObject.transform.localRotation*vLabel.CanvasLocalRotation;
			vIcon.transform.localScale = GetIconScale();
			vIcon.AddComponent<MeshRenderer>();

			MeshFilter iconFilt = vIcon.AddComponent<MeshFilter>();
			vIconMeshBuilder = new MeshBuilder();
			MeshUtil.BuildQuadMesh(vIconMeshBuilder);
			Materials.SetMeshIconCoords(vIconMeshBuilder, GetIconOffset());
			vIconMeshBuilder.Commit();
			vIconMeshBuilder.CommitColors(Color.clear);
			iconFilt.sharedMesh = vIconMeshBuilder.Mesh;
		}
		////////////////////////////////////////////////////////////////////////////////////////////////
		/*--------------------------------------------------------------------------------------------*/
		public virtual void Build(IHovercastMenuState pMenuState, IBaseItemState pItemState,
													float pArcAngle, IItemVisualSettings pSettings) {
			vMenuState = pMenuState;
			vItemState = pItemState;
			vAngle0 = -pArcAngle/2f;
			vAngle1 = pArcAngle/2f;
			vSettings = (ItemVisualSettingsStandard)pSettings;
			vSliderItem = (ISliderItem)vItemState.Item;
			vTicks = new GameObject[vSliderItem.Ticks];

			const float pi = (float)Math.PI;

			vGrabArc = pi/40f;
			vSlideDegree0 = (vAngle0+vGrabArc/2)/pi*180;
			vSlideDegrees = (vAngle1-vAngle0-vGrabArc)/pi*180;
			vZeroValue = (0-vSliderItem.RangeMin)/(vSliderItem.RangeMax-vSliderItem.RangeMin);

			////

			vHiddenSlice = new UiHoverMeshSlice(gameObject, true);
			vHiddenSlice.UpdateSize(1, 1.5f, pArcAngle);
			vHiddenSlice.UpdateBackground(Color.clear);

			var trackObj = new GameObject("Track");
			trackObj.transform.SetParent(gameObject.transform, false);
			trackObj.transform.localRotation = Quaternion.AngleAxis(vAngle0/pi*180, Vector3.up);

			vTrack = new UiItemSliderTrackRenderer(trackObj);
			vTrackSegments = new ReadList<DisplayUtil.TrackSegment>();
			vTrackCuts = new ReadList<DisplayUtil.TrackSegment>();

			////

			if ( vSliderItem.Ticks > 1 ) {
				Vector3 quadScale = new Vector3(UiHoverMeshSlice.AngleInset*2, 0.36f, 0.1f);
				float percPerTick = 1/(float)(vSliderItem.Ticks-1);

				vTickMeshBuilder = new MeshBuilder();
				MeshUtil.BuildQuadMesh(vTickMeshBuilder);
				vTickMeshBuilder.Commit();
				vTickMeshBuilder.CommitColors(Color.clear);

				for ( int i = 0 ; i < vSliderItem.Ticks ; ++i ) {
					var tickObj = new GameObject("Tick"+i);
					tickObj.transform.SetParent(gameObject.transform, false);
					tickObj.transform.localRotation = Quaternion.AngleAxis(
						vSlideDegree0+vSlideDegrees*i*percPerTick, Vector3.up);
					vTicks[i] = tickObj;

					var quadObj = new GameObject("Quad");
					quadObj.transform.SetParent(tickObj.transform, false);
					quadObj.transform.localPosition = new Vector3(0, 0, 1.25f);
					quadObj.transform.localRotation = TickQuatRot;
					quadObj.transform.localScale = quadScale;
					quadObj.AddComponent<MeshRenderer>();

					MeshFilter quadFilt = quadObj.AddComponent<MeshFilter>();
					quadFilt.sharedMesh = vTickMeshBuilder.Mesh;
				}
			}

			////

			vGrabHold = new GameObject("GrabHold");
			vGrabHold.transform.SetParent(gameObject.transform, false);

			var grabObj = new GameObject("Grab");
			grabObj.transform.SetParent(vGrabHold.transform, false);

			vGrab = grabObj.AddComponent<UiItemSliderGrabRenderer>();
			vGrab.Build(vMenuState, vItemState, vGrabArc, pSettings);

			////

			vHoverHold = new GameObject("HoverHold");
			vHoverHold.transform.SetParent(gameObject.transform, false);

			var hoverObj = new GameObject("Hover");
			hoverObj.transform.SetParent(vHoverHold.transform, false);

			vHover = new UiHoverMeshSlice(hoverObj, false, "Hover");
		}
		////////////////////////////////////////////////////////////////////////////////////////////////
		/*--------------------------------------------------------------------------------------------*/
		protected override void UpdateMesh(MeshType pType, MeshBuilder pMeshBuild, float pAmount=1) {
			if ( pType == MeshType.Edge ) {
				float edgeInner = (DrawOuterEdge ? vRadOuter : vRadInner-EdgeThick);
				float edgeOuter = (DrawOuterEdge ? vRadOuter+EdgeThick : vRadInner);
				MeshUtil.BuildRingMesh(pMeshBuild, edgeInner, edgeOuter, vAngle0, vAngle1, vMeshSteps);
				pMeshBuild.Commit();
				return;
			}

			float radOuter = vRadInner+(vRadOuter-vRadInner)*pAmount;

			MeshUtil.BuildRingMesh(pMeshBuild, vRadInner, radOuter, vAngle0, vAngle1, vMeshSteps);
			pMeshBuild.Commit();
		}
		////////////////////////////////////////////////////////////////////////////////////////////////
		/*--------------------------------------------------------------------------------------------*/
		public virtual void Build(IHoverboardPanelState pPanelState,
										IHoverboardLayoutState pLayoutState, IBaseItemState pItemState,
										IItemVisualSettings pSettings) {
			vPanelState = pPanelState;
			vLayoutState = pLayoutState;
			vItemState = pItemState;
			vSettings = (ItemVisualSettingsStandard)pSettings;
			vSliderItem = (ISliderItem)vItemState.Item;
			vTicks = new GameObject[vSliderItem.Ticks];

			vWidth = UiItem.Size*vSliderItem.Width;
			vHeight = UiItem.Size*vSliderItem.Height;
			vIsVert = (vHeight > vWidth);
			vGrabW = 1;
			vZeroValue = (0-vSliderItem.RangeMin)/(vSliderItem.RangeMax-vSliderItem.RangeMin);

			gameObject.transform.SetParent(gameObject.transform, false);
			gameObject.transform.localPosition = new Vector3(vWidth/2, 0, vHeight/2f);
			gameObject.transform.localRotation = Quaternion.AngleAxis((vIsVert ? 90 : 0), Vector3.up);

			if ( vIsVert ) { //swap dimensions here + rotate graphics later
				float tempW = vWidth;
				vWidth = vHeight;
				vHeight = tempW;
			}

			vSlideX0 = (vGrabW-vWidth)/2;
			vSlideW = vWidth-vGrabW;

			////

			vHiddenRect = new UiHoverMeshRectBg(gameObject);
			vHiddenRect.UpdateSize(vWidth, vHeight);

			var trackObj = new GameObject("Track");
			trackObj.transform.SetParent(gameObject.transform, false);
			trackObj.transform.localPosition = new Vector3(-vWidth/2, 0, 0);

			vTrack = new UiItemSliderTrackRenderer(trackObj);
			vTrackSegments = new ReadList<DisplayUtil.TrackSegment>();
			vTrackCuts = new ReadList<DisplayUtil.TrackSegment>();

			////

			if ( vSliderItem.Ticks > 1 ) {
				Vector3 quadScale = new Vector3(UiHoverMeshRect.SizeInset*2, 0.36f, 0.1f);
				float percPerTick = 1/(float)(vSliderItem.Ticks-1);

				vTickMeshBuilder = new MeshBuilder();
				MeshUtil.BuildQuadMesh(vTickMeshBuilder);
				vTickMeshBuilder.Commit();
				vTickMeshBuilder.CommitColors(Color.clear);

				for ( int i = 0 ; i < vSliderItem.Ticks ; ++i ) {
					GameObject tickObj = new GameObject("Tick"+i);
					tickObj.transform.SetParent(gameObject.transform, false);
					tickObj.transform.localPosition = Vector3.right*(vSlideX0+vSlideW*i*percPerTick);
					tickObj.transform.localRotation = TickQuatRot;
					tickObj.transform.localScale = quadScale;
					tickObj.AddComponent<MeshRenderer>();

					MeshFilter tickFilt = tickObj.AddComponent<MeshFilter>();
					tickFilt.sharedMesh = vTickMeshBuilder.Mesh;

					vTicks[i] = tickObj;
				}
			}

			////

			vGrabHold = new GameObject("GrabHold");
			vGrabHold.transform.SetParent(gameObject.transform, false);
			vGrabHold.transform.localRotation = Quaternion.Inverse(gameObject.transform.localRotation);

			var grabObj = new GameObject("Grab");
			grabObj.transform.SetParent(vGrabHold.transform, false);

			vGrab = grabObj.AddComponent<UiItemSliderGrabRenderer>();
			vGrab.IsVert = vIsVert;
			vGrab.Build(vPanelState, vLayoutState, vItemState, vSettings);

			if ( vIsVert ) {
				vGrab.SetCustomSize(vHeight, vGrabW, false);
			}
			else {
				vGrab.SetCustomSize(vGrabW, vHeight, false);
			}

			////

			vHoverHold = new GameObject("HoverHold");
			vHoverHold.transform.SetParent(gameObject.transform, false);

			var hoverObj = new GameObject("Hover");
			hoverObj.transform.SetParent(vHoverHold.transform, false);

			vHover = new UiHoverMeshRect(hoverObj, "Hover");
		}
		////////////////////////////////////////////////////////////////////////////////////////////////
		/*--------------------------------------------------------------------------------------------*/
		protected override void UpdateMesh(MeshType pType, MeshBuilder pMeshBuild, float pAmount=1) {
			MeshUtil.BuildRectangleMesh(pMeshBuild, vMeshW, vMeshH, pAmount);
			pMeshBuild.Commit();
		}