using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using DOFerVolumeRenderer.Components;


namespace DOFerVolumeRenderer
{
	/// <summary>
	/// This is a game component that implements IUpdateable.
	/// </summary>
	public class TransferFunctionEditorComponent : Microsoft.Xna.Framework.DrawableGameComponent
	{
		private Game m_game;
		private IRenderTargetProvider m_renderTargetProvider;
		private ITransferFunctionProvider m_transferFunctionProvider;
		private IVolumeDataProvider m_volumeDataProvider;
		private IInputHelper m_inputHelper;
		private ICamera m_camera = null;
		private IVolumeRendererSettings m_settings = null;

		private Texture2D m_cpTex = null;
		private Texture2D m_cpSelTex = null;
		private Texture2D m_ctrlLmbTex = null;
		private Texture2D m_ctrlRmbTex = null;
		private Texture2D m_mwTex = null;
		private Texture2D m_whiteTex = null;
		private Texture2D m_fuckYea = null;

		private Effect m_colorPickerFx = null;

		private bool m_shouldUpdateTrafu = false;

		private ColorPicker m_colorPicker = null;

		private SpriteFont m_font = null;

		#region le GUI elements

		private const int TRFU_X = 58;
		private const int TRFU_Y = 580;
		private const int TRFU_WIDTH = 680;
		private const int TRFU_HEIGHT = 200;
		private const int TRFU_LBLOFFLEFT = 35;
		private const int TRFU_LBLOFFRIGHT = 5;
		private const int CPSIZE = 20;
		private const int HALF_CPSIZE = CPSIZE >> 1;
		private const int COLORPICKER_OFFSET = 80;
		private const int COLORPICKER_WIDTH = 280;
		private const int CPCOL_OFFSET = 20;
		private const int CPCOL_WIDTH = 60;
		private const int CPCOL_HEIGHT = 40;
		private const float TRAFULBL_SCALE = 0.7f;
		
		private readonly Rectangle m_guiArea = new Rectangle(0, 517, 1600, 340);

		private readonly Rectangle m_trafuArea = new Rectangle(TRFU_X, TRFU_Y, TRFU_WIDTH, TRFU_HEIGHT);
		private readonly Rectangle m_trafuBorderTop = new Rectangle(TRFU_X - 1, TRFU_Y - 1, TRFU_WIDTH + 2, 1);
		private readonly Rectangle m_trafuBorderBottom = new Rectangle(TRFU_X - 1, TRFU_Y + TRFU_HEIGHT, TRFU_WIDTH + 2, 1);
		private readonly Rectangle m_trafuBorderLeft = new Rectangle(TRFU_X - 1, TRFU_Y - 1, 1, TRFU_HEIGHT + 2);
		private readonly Rectangle m_trafuBorderRight = new Rectangle(TRFU_X + TRFU_WIDTH, TRFU_Y - 1, 1, TRFU_HEIGHT + 2);

		private readonly Rectangle m_colorPickerArea = new Rectangle(TRFU_X + TRFU_WIDTH + COLORPICKER_OFFSET, TRFU_Y, COLORPICKER_WIDTH, TRFU_HEIGHT);
		private readonly Rectangle m_colorPickerBorderTop = new Rectangle(TRFU_X + TRFU_WIDTH + COLORPICKER_OFFSET - 1, TRFU_Y - 1, COLORPICKER_WIDTH + 2, 1);
		private readonly Rectangle m_colorPickerBorderBottom = new Rectangle(TRFU_X + TRFU_WIDTH + COLORPICKER_OFFSET - 1, TRFU_Y + TRFU_HEIGHT, COLORPICKER_WIDTH + 2, 1);
		private readonly Rectangle m_colorPickerBorderLeft = new Rectangle(TRFU_X + TRFU_WIDTH + COLORPICKER_OFFSET - 1, TRFU_Y - 1, 1, TRFU_HEIGHT + 2);
		private readonly Rectangle m_colorPickerBorderRight = new Rectangle(TRFU_X + TRFU_WIDTH + COLORPICKER_OFFSET + COLORPICKER_WIDTH, TRFU_Y - 1, 1, TRFU_HEIGHT + 2);

		private readonly Rectangle m_cpColArea = new Rectangle(TRFU_X + TRFU_WIDTH + COLORPICKER_OFFSET + COLORPICKER_WIDTH + CPCOL_OFFSET, TRFU_Y, CPCOL_WIDTH, CPCOL_HEIGHT);
		private readonly Rectangle m_cpColTop = new Rectangle(TRFU_X + TRFU_WIDTH + COLORPICKER_OFFSET + COLORPICKER_WIDTH + CPCOL_OFFSET - 1, TRFU_Y - 1, CPCOL_WIDTH + 2, 1);
		private readonly Rectangle m_cpColBottom = new Rectangle(TRFU_X + TRFU_WIDTH + COLORPICKER_OFFSET + COLORPICKER_WIDTH + CPCOL_OFFSET - 1, TRFU_Y + CPCOL_HEIGHT, CPCOL_WIDTH + 2, 1);
		private readonly Rectangle m_cpColLeft = new Rectangle(TRFU_X + TRFU_WIDTH + COLORPICKER_OFFSET + COLORPICKER_WIDTH + CPCOL_OFFSET - 1, TRFU_Y - 1, 1, CPCOL_HEIGHT + 2);
		private readonly Rectangle m_cpColRight = new Rectangle(TRFU_X + TRFU_WIDTH + COLORPICKER_OFFSET + COLORPICKER_WIDTH + CPCOL_OFFSET + CPCOL_WIDTH, TRFU_Y - 1, 1, CPCOL_HEIGHT + 2);

		private readonly Vector2 m_trafuLblOrigin = new Vector2(0f, 0f);

		#endregion

		#region Positions of the gui-elements

		private readonly Rectangle m_fuckYeaRect = new Rectangle(20, 9, 256, 64);
		private readonly Rectangle m_fuckYeaStrich = new Rectangle(0, 74, 434, 3);
		private readonly Rectangle m_fuckYeaBg = new Rectangle(3, 3, 428, 70);

		private readonly Rectangle m_tabHint = new Rectangle(20, 86, 64, 32);
		private readonly Rectangle m_mouseWheelHint = new Rectangle(20, 116, 64, 32);
		private readonly Rectangle m_createHint = new Rectangle(20, 152, 64, 32);
		private readonly Rectangle m_deleteHint = new Rectangle(20, 188, 64, 32);
		private readonly Vector2 m_otherHintsStart = new Vector2(20, 226);
		private const float HINTS_HEIGHT = 32f;

		#endregion

		private ControlPoint m_selectedCp = null;
		private bool m_dragging = false;
		private bool m_draggingColPick = false;

		public TransferFunctionEditorComponent(Game game)
			: base(game)
		{
			m_game = game;
		}


		protected override void LoadContent()
		{
			m_cpTex = m_game.Content.Load<Texture2D>("GUI/controlpoint");
			m_cpSelTex = m_game.Content.Load<Texture2D>("GUI/controlpoint_sel");
			m_ctrlLmbTex = m_game.Content.Load<Texture2D>("GUI/ctrl+lmb");
			m_ctrlRmbTex = m_game.Content.Load<Texture2D>("GUI/ctrl+rmb");
			m_mwTex = m_game.Content.Load<Texture2D>("GUI/mousewheel");
			m_whiteTex = m_game.Content.Load<Texture2D>("GUI/white");
			m_colorPickerFx = m_game.Content.Load<Effect>("Shaders/ColorPicker");
			m_font = m_game.Content.Load<SpriteFont>("Fonts/UIFont");
			m_fuckYea = m_game.Content.Load<Texture2D>("GUI/DOFyeaW");
		}


		/// <summary>
		/// Allows the game component to perform any initialization it needs to before starting
		/// to run.  This is where it can query for any required services and load content.
		/// </summary>
		public override void Initialize()
		{
			m_renderTargetProvider = m_game.Services.GetService(typeof(IRenderTargetProvider)) as IRenderTargetProvider;
			m_transferFunctionProvider = m_game.Services.GetService(typeof(ITransferFunctionProvider)) as ITransferFunctionProvider;
			m_volumeDataProvider = m_game.Services.GetService(typeof(IVolumeDataProvider)) as IVolumeDataProvider;
			m_inputHelper = m_game.Services.GetService(typeof(IInputHelper)) as IInputHelper;
			m_camera = m_game.Services.GetService(typeof(ICamera)) as ICamera;
			m_settings = m_game.Services.GetService(typeof(IVolumeRendererSettings)) as IVolumeRendererSettings;

			m_colorPicker = new ColorPicker(m_game, 256);

			base.Initialize();
		}


		private bool GetMousePositionOnTransferFu(out Vector2 relativeMousePos)
		{
			var mouseX = m_inputHelper.MouseState.X;
			var mouseY = m_inputHelper.MouseState.Y;
			if (mouseX >= m_trafuArea.Left - CPSIZE && mouseX <= m_trafuArea.Right + CPSIZE && mouseY >= m_trafuArea.Top - CPSIZE && mouseY <= m_trafuArea.Bottom + CPSIZE)
			{
				relativeMousePos = new Vector2(
					(float)(mouseX - m_trafuArea.Left) / m_trafuArea.Width,
					(float)(mouseY - m_trafuArea.Top) / m_trafuArea.Height
					);
				return true;
			}
			relativeMousePos = new Vector2();
			return false;
		}

		private bool GetMousePositionOnColorPicker(out Vector2 relativeMousePos)
		{
			var mouseX = m_inputHelper.MouseState.X;
			var mouseY = m_inputHelper.MouseState.Y;
			if (mouseX >= m_colorPickerArea.Left && mouseX <= m_colorPickerArea.Right && mouseY >= m_colorPickerArea.Top && mouseY <= m_colorPickerArea.Bottom)
			{
				relativeMousePos = new Vector2(
					(float)(mouseX - m_colorPickerArea.Left) / m_colorPickerArea.Width,
					(float)(mouseY - m_colorPickerArea.Top) / m_colorPickerArea.Height
					);
				return true;
			}
			relativeMousePos = new Vector2();
			return false;
		}


		private float ModifyAlpha(float alpha)
		{
			return alpha * alpha;
		}

		private float InvModifyAlpha(float alpha)
		{
			return (float)Math.Sqrt(alpha);
		}


		/// <summary>
		/// Allows the game component to update itself.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		public override void Update(GameTime gameTime)
		{
			// Set the alpha-factor regardless of being in CameraMode or not
			m_settings.BlurFactor += m_inputHelper.ScrollWheelChange * 0.01f;


			float AChange = (float)(50.0 * gameTime.ElapsedGameTime.TotalSeconds);
			if (m_inputHelper.KeyboardState.IsKeyDown(Keys.OemMinus))
			{
				m_settings.AlphaFactor -= AChange;
			}
			if (m_inputHelper.KeyboardState.IsKeyDown(Keys.OemPlus))
			{
				m_settings.AlphaFactor += AChange;
			}



			if (m_inputHelper.IsNewKeyPress(Keys.B))
			{
				m_settings.BlurEnabled = !m_settings.BlurEnabled;
			}



			if (m_inputHelper.IsNewKeyPress(Keys.G))
			{
				m_settings.GradientsEnabled = !m_settings.GradientsEnabled;
			}



			// Settings only active if in CameraMode (changed via Tab-key)
			if (CameraMode.MenuMode == m_camera.CameraMode)
			{
				TransferFunction trafu = m_transferFunctionProvider.GetTransferFunction();
				Vector2 relMousePos;
				if (null != trafu && GetMousePositionOnTransferFu(out relMousePos))
				{

					if (m_dragging && null != m_selectedCp)
					{
						if (m_inputHelper.MouseState.LeftButton != ButtonState.Pressed)
						{
							m_dragging = false;
						}
						else
						{
							// drag!
							trafu.MoveControlPointToPosition(m_selectedCp, relMousePos.X);
							m_selectedCp.Color = new Color(m_selectedCp.Color.R, m_selectedCp.Color.G, m_selectedCp.Color.B, (byte)Math.Max(0, Math.Min(255, (int)(255 * ModifyAlpha(1.0f - relMousePos.Y)))));
							m_shouldUpdateTrafu = true;
						}
					}

					ControlPoint cpAtPos;
					if (trafu.GetControlPointAtPosition(relMousePos.X, out cpAtPos))
					{
						// check if user really hit the CPSIZE x CPSIZE area
						var guiPos = CalcCpGuiPosition(cpAtPos);
						if (Math.Abs(guiPos.X + HALF_CPSIZE - m_inputHelper.MouseState.X) < HALF_CPSIZE && Math.Abs(guiPos.Y + HALF_CPSIZE - m_inputHelper.MouseState.Y) < HALF_CPSIZE)
						{
							// => hit!
							if (m_inputHelper.IsNewLMBPress())
							{
								m_selectedCp = cpAtPos;
								m_dragging = true;
							}
							else if (m_inputHelper.IsNewRMBPress() && m_inputHelper.KeyboardState.IsKeyDown(Keys.LeftControl))
							{
								trafu.DeleteControlPoint(cpAtPos);
								m_shouldUpdateTrafu = true;
							}
						}
					}
					else
					{
						if (m_inputHelper.IsNewLMBPress() && m_inputHelper.KeyboardState.IsKeyDown(Keys.LeftControl))
						{
							// there is no control point => create a new one
							trafu.CreateControlPointAtPosition(relMousePos.X, ModifyAlpha(1.0f - relMousePos.Y));
							m_shouldUpdateTrafu = true;
						}
					}
				}
				else // => outside of transfer-box
				{
					m_dragging = false;
				}

				// le color-picker check0rs
				if (null != m_selectedCp)
				{
					if (m_draggingColPick)
					{
						if (m_inputHelper.MouseState.LeftButton != ButtonState.Pressed)
						{
							m_draggingColPick = false;
						}
					}

					Vector2 colPickMousePos;
					if (GetMousePositionOnColorPicker(out colPickMousePos))
					{
						if (m_inputHelper.IsNewLMBPress())
						{
							m_draggingColPick = true;
						}

						if (m_draggingColPick && m_inputHelper.MouseState.LeftButton == ButtonState.Pressed)
						{
							Color colPickColor = m_colorPicker.GetColorAtPos(colPickMousePos.X, colPickMousePos.Y);
							m_selectedCp.Color = new Color(colPickColor.R, colPickColor.G, colPickColor.B, m_selectedCp.Color.A);
							m_shouldUpdateTrafu = true;
						}
					}
					else // => outside of color-picker box
					{
						m_draggingColPick = false;
					}
				}
			}
		}

		private Rectangle CalcCpGuiPosition(ControlPoint cp)
		{
			return new Rectangle(
					TRFU_X + (int)(cp.Position * TRFU_WIDTH) - HALF_CPSIZE,
					TRFU_Y + (int)((1.0f - InvModifyAlpha((float)cp.Color.A / byte.MaxValue)) * TRFU_HEIGHT) - HALF_CPSIZE,
					CPSIZE, 
					CPSIZE
				);
		}

		/// <summary>
		/// Draw the Editing controls
		/// </summary>
		/// <param name="gameTime"></param>
		public override void Draw(GameTime gameTime)
		{
			using (SpriteBatch sb = new SpriteBatch(m_game.GraphicsDevice))
			{
				// ****** GUI-Area Background, Transfer function border, Color picker border, Color picker *******
				sb.Begin(SpriteSortMode.Deferred, BlendState.Opaque);
				sb.Draw(m_whiteTex, m_guiArea, Color.Black);
				
				// draw border around transfer-function
				sb.Draw(m_whiteTex, m_trafuBorderTop, Color.White);
				sb.Draw(m_whiteTex, m_trafuBorderBottom, Color.White);
				sb.Draw(m_whiteTex, m_trafuBorderLeft, Color.White);
				sb.Draw(m_whiteTex, m_trafuBorderRight, Color.White);

				// draw color-picker border
				sb.Draw(m_whiteTex, m_colorPickerBorderTop, Color.White);
				sb.Draw(m_whiteTex, m_colorPickerBorderBottom, Color.White);
				sb.Draw(m_whiteTex, m_colorPickerBorderLeft, Color.White);
				sb.Draw(m_whiteTex, m_colorPickerBorderRight, Color.White);

				// draw color-picker
				sb.Draw(m_colorPicker.Texture, m_colorPickerArea, Color.White);

				// draw control-points border
				sb.Draw(m_whiteTex, m_cpColTop, Color.White);
				sb.Draw(m_whiteTex, m_cpColBottom, Color.White);
				sb.Draw(m_whiteTex, m_cpColLeft, Color.White);
				sb.Draw(m_whiteTex, m_cpColRight, Color.White);

				// draw fuck yea bg and strich
				sb.Draw(m_whiteTex, m_fuckYeaBg, Color.White);
				sb.Draw(m_whiteTex, m_fuckYeaStrich, Color.Black);

				// draw control-point's color
				if (null != m_selectedCp)
				{
					sb.Draw(m_whiteTex, m_cpColArea, new Color(m_selectedCp.Color.R, m_selectedCp.Color.G, m_selectedCp.Color.B, 255));
				}

				sb.End();

				// ****** Transfer function *******
				sb.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
				sb.Draw(m_transferFunctionProvider.GetTransferFunction().Texture, m_trafuArea, Color.White);
				sb.End();
	
				sb.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
				foreach (var cp in m_transferFunctionProvider.GetTransferFunction().ControlPoints)
				{
					if (cp == m_selectedCp)
						sb.Draw(m_cpSelTex, CalcCpGuiPosition(cp), Color.White);
					else 
						sb.Draw(m_cpTex, CalcCpGuiPosition(cp), Color.White);
				}

				// draw user hints
				sb.Draw(m_mwTex, m_mouseWheelHint, Color.White);
				sb.Draw(m_ctrlLmbTex, m_createHint, Color.White);
				sb.Draw(m_ctrlRmbTex, m_deleteHint, Color.White);

				// FUCK YEA
				sb.Draw(m_fuckYea, m_fuckYeaRect, Color.White);
				
				sb.DrawString(m_font, string.Format("TAB ... Switch modes, currently in {0}", m_camera.CameraMode.ToString()), new Vector2(m_tabHint.X, m_tabHint.Y), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, "Create new control-point (in MenuMode)", new Vector2(m_createHint.X + 72, m_createHint.Y + 4), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, "Delete control-point (in MenuMode)", new Vector2(m_deleteHint.X + 72, m_deleteHint.Y + 4), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, string.Format("Blur factor: {0:0.0}", m_settings.BlurFactor), new Vector2(m_mouseWheelHint.X + 72, m_mouseWheelHint.Y + 4), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, string.Format("B ... {0} blur, currently {1}", m_settings.BlurEnabled ? "disable" : "enable", m_settings.BlurEnabled ? "enabled" : "disabled"), m_otherHintsStart, Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, string.Format("+/- ... change alpha-factor: {0:0.0}", m_settings.AlphaFactor), new Vector2(m_otherHintsStart.X, m_otherHintsStart.Y + HINTS_HEIGHT), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, "PgUp/PgDn ... Move focus plane", new Vector2(m_otherHintsStart.X, m_otherHintsStart.Y + 2 * HINTS_HEIGHT), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, string.Format("G ... {0} gradients, currently {1}", m_settings.GradientsEnabled ? "disable" : "enable", m_settings.GradientsEnabled ? "enabled" : "disabled"), new Vector2(m_otherHintsStart.X, m_otherHintsStart.Y + 3 * HINTS_HEIGHT), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, "T ... switch transfer function", new Vector2(m_otherHintsStart.X, m_otherHintsStart.Y + 4 * HINTS_HEIGHT), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, "V ... switch volume-data", new Vector2(m_otherHintsStart.X, m_otherHintsStart.Y + 5 * HINTS_HEIGHT), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, "F ... show/hide focus point", new Vector2(m_otherHintsStart.X, m_otherHintsStart.Y + 6 * HINTS_HEIGHT), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, "W A S D ... move", new Vector2(m_otherHintsStart.X, m_otherHintsStart.Y + 7 * HINTS_HEIGHT), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, "Mouse ... look (in FPSMode)", new Vector2(m_otherHintsStart.X, m_otherHintsStart.Y + 8 * HINTS_HEIGHT), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);

				sb.DrawString(m_font, "Transfer Function", new Vector2(m_trafuArea.X, m_trafuArea.Y - 32), Color.White, 0f, Vector2.Zero, 1.0f, SpriteEffects.None, 1);
				sb.DrawString(m_font, "RESULT", new Vector2(696, 3), Color.White, 0f, Vector2.Zero, 0.8f, SpriteEffects.None, 1);
				sb.DrawString(m_font, "BACK SLICES", new Vector2(438, 3), Color.White, 0f, Vector2.Zero, 0.6f, SpriteEffects.None, 1);
				sb.DrawString(m_font, "FRONT SLICES", new Vector2(438, 262), Color.White, 0f, Vector2.Zero, 0.6f, SpriteEffects.None, 1);

				// draw alpha-labels to the transfer-function
				sb.DrawString(m_font, "1.0", new Vector2(TRFU_X - TRFU_LBLOFFLEFT, TRFU_Y + (int)((1.0f - InvModifyAlpha(1.0f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);
				sb.DrawString(m_font, "0.5", new Vector2(TRFU_X - TRFU_LBLOFFLEFT, TRFU_Y + (int)((1.0f - InvModifyAlpha(.5f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);
				sb.DrawString(m_font, "0.25", new Vector2(TRFU_X - TRFU_LBLOFFLEFT, TRFU_Y + (int)((1.0f - InvModifyAlpha(.25f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);
				sb.DrawString(m_font, "0.12", new Vector2(TRFU_X - TRFU_LBLOFFLEFT, TRFU_Y + (int)((1.0f - InvModifyAlpha(.12f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);
				sb.DrawString(m_font, "0.05", new Vector2(TRFU_X - TRFU_LBLOFFLEFT, TRFU_Y + (int)((1.0f - InvModifyAlpha(.05f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);
				sb.DrawString(m_font, "0.01", new Vector2(TRFU_X - TRFU_LBLOFFLEFT, TRFU_Y + (int)((1.0f - InvModifyAlpha(.01f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);
				sb.DrawString(m_font, "0.0", new Vector2(TRFU_X - TRFU_LBLOFFLEFT, TRFU_Y + (int)((1.0f - InvModifyAlpha(0.0f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);

				// draw alpha-labels again, on the right hand site
				sb.DrawString(m_font, "1.0", new Vector2(TRFU_WIDTH + TRFU_X + TRFU_LBLOFFRIGHT, TRFU_Y + (int)((1.0f - InvModifyAlpha(1.0f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);
				sb.DrawString(m_font, "0.5", new Vector2(TRFU_WIDTH + TRFU_X + TRFU_LBLOFFRIGHT, TRFU_Y + (int)((1.0f - InvModifyAlpha(.5f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);
				sb.DrawString(m_font, "0.25", new Vector2(TRFU_WIDTH + TRFU_X + TRFU_LBLOFFRIGHT, TRFU_Y + (int)((1.0f - InvModifyAlpha(.25f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);
				sb.DrawString(m_font, "0.12", new Vector2(TRFU_WIDTH + TRFU_X + TRFU_LBLOFFRIGHT, TRFU_Y + (int)((1.0f - InvModifyAlpha(.12f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);
				sb.DrawString(m_font, "0.05", new Vector2(TRFU_WIDTH + TRFU_X + TRFU_LBLOFFRIGHT, TRFU_Y + (int)((1.0f - InvModifyAlpha(.05f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);
				sb.DrawString(m_font, "0.01", new Vector2(TRFU_WIDTH + TRFU_X + TRFU_LBLOFFRIGHT, TRFU_Y + (int)((1.0f - InvModifyAlpha(.01f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);
				sb.DrawString(m_font, "0.0", new Vector2(TRFU_WIDTH + TRFU_X + TRFU_LBLOFFRIGHT, TRFU_Y + (int)((1.0f - InvModifyAlpha(0.0f)) * TRFU_HEIGHT) - 8), Color.White, 0f, m_trafuLblOrigin, TRAFULBL_SCALE, SpriteEffects.None, 0);

				sb.End();
			}

			if (m_shouldUpdateTrafu)
			{
				m_game.GraphicsDevice.Textures[0] = null;
				m_transferFunctionProvider.GetTransferFunction().Update();
				m_shouldUpdateTrafu = false;
			}
		}
	}
}
