

#include "windows.h"
#include "math.h"
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "globals.h"
#include "gigeapp.h"
#include "dxquad.h"
#include "prefsXML.h"
#include "uiiridas.h"
#include "lut3d.h"
#include "uilook.h"
#include "logger.h"
#include "uimanager.h"

void OnSaveLookFile( int, int );
extern	void CheckFileExtension( char * fileName, EFileType fileType );
extern void OnLoadFrame( int x,int y );
extern bool AddStereoFile( char *playbackPath, std::vector<char*> *SIVPlaybackPaths );
extern void OpenFileDialog( EFileType type, char *destText );

#define NUM_SLIDERS 6

char *offsetStr[IRIDAS_MODE_LAST] = {
	"offset",
	"offsetHigh",
	"offsetMid",
	"offsetLow"
};


char *gammaStr[IRIDAS_MODE_LAST] = {
	"gamma",
	"gammaHigh",
	"gammaMid",
	"gammaLow"
};

char *colorGainStr[IRIDAS_MODE_LAST] = {
	"gain",
	"gainHigh",
	"gainMid",
	"gainLow"
};

char *sliderStr[IRIDAS_SLIDER_LAST][IRIDAS_MODE_LAST] = {
	{
		"saturation",
		"saturationLMH.Z",
		"saturationLMH.Y",
		"saturationLMH.X"
	},
	{
		"Pivot",
		"PivotHigh",
		"PivotMid",
		"PivotLow"
	},
	{
		"Temperature",
		"TemperatureHigh",
		"TemperatureMid",
		"TemperatureLow"
	},
	{
		"Overall",
		"OverallHigh",
		"OverallMid",
		"OverallLow"
	},
	{
		"Contrast",
		"ContrastHigh",
		"ContrastMid",
		"ContrastLow"
	},
	{
		"Magenta",
		"MagentaHigh",
		"MagentaMid",
		"MagentaLow"
	}
};

double sliderMinMidMax[IRIDAS_SLIDER_LAST][3]= {
	{
		0, 1, 2
	},
	{
		0, 0.5, 1
	},
	{
		-1, 0, 1
	},
	{
		-1, 0, 1
	},
	{
		-1, 0, 1
	},
	{
		-1, 0, 1
	}
};
	
SIrexILook* gIrex = NULL;
CUIIridas *gIridas = NULL;
SIrexISDI* gIrexSdi = NULL;

bool hasLookAlpha( char *filename, float *iridasVector )
{
	if ( !gIrex )
		return false;

	char lookpath[256];
	strcpy(lookpath,Globals.GetSIDir());
	strcat(lookpath,filename);

	IRBOOL loaded = gIrex->bLoadLook( lookpath );
	if ( !loaded )
	{
		return false;
	}

	// load AlphaKeyerRGB
	char shaderName[256];
	unsigned int shaderNameLength;
	unsigned int numLayers = gIrex->nGetLookLayerCount();
	for ( unsigned int i = 0; i < numLayers; i++ )
	{
		gIrex->bGetLookShaderName( i, shaderName, &shaderNameLength );
		if ( !strcmp( shaderName, "fxKeyer" ) )
		{
			if ( iridasVector )
			{
				double temp;
				char str[32];
	
				sprintf(str,"%d.screenColor",i);
				temp = gIrex->dReadLookScalarValue( str	);
				iridasVector[0] = (float) temp;

				sprintf(str,"%d.scaleToOne",i);
				temp = gIrex->dReadLookScalarValue( str	);
				if ( temp == 0 ) temp = IRI_THRESHOLD_MIN;
				iridasVector[1] = 1.0f / (float) temp;
			}
			return true;
		}
	}

	return false;
}


CUIIridas::CUIIridas( char *filename, int index )
{
	mIndex = index;
	mSet1List = NULL;
	mSet2List = NULL;
	mSet3List = NULL;
	mOkButton = NULL;
	mDoneButton = NULL;
	mLookFileDialog = NULL;
	mSet = 0;
	strcpy( mFilename, filename );
	strcpy( mLoadLook, filename );
	strcpy( mSaveLook, "\0" );

	mIridasMode = IRIDAS_MODE_OVERALL;
	mKeyerMode = IRIDAS_KEYERMODE_FG;
	mHistogramMode = true;
	mGreyOn = true;

	mTrackballOn = false;
	mTrackballButton = -1;
	mTrackballX = 0;
	mTrackballY = 0;

	mKeyerInfo.mExists = false;
	mKeyerInfo.mColor = -1;
	mKeyerInfo.mScale = IRI_THRESHOLD_DEFAULT;
	mKeyerInfo.mColorName[0] = 0;
	mKeyerInfo.mScaleName[0] = 0;
	Globals.mIridasVector[0] = (float) mKeyerInfo.mColor;
	if ( mKeyerInfo.mScale <= IRI_THRESHOLD_MIN ) 
	{
		mKeyerInfo.mScale = IRI_THRESHOLD_MIN;
	}
	Globals.mIridasVector[1] = (float) ( 1.0 / mKeyerInfo.mScale );

	if ( isProgramPlayingAVI() || isProgramPlayingSIV() )
		mActiveLook = gPrefs.GetPlayerLook();
	else if ( gPrefs.GetPreviewLookActive() )
		mActiveLook = gPrefs.GetViewLook();
	else
		mActiveLook = gPrefs.GetRecordLook();

	for ( int i = 0; i < 256; i++ )
		mLut8[i] = (float) i / 255.0f;

	mValChanged = false;

	Init();	
	Reset();
	Load( mFilename );
	UpdateHSL();
	Update();
}



CUIIridas::~CUIIridas()
{
	
}

void CUIIridas::Reset( void )
{
	mOffsetLuma = 0;
	mOffsetPos[0] = 0;
	mOffsetPos[1] = 0;

	mGammaLuma = 0;
	mGammaPos[0] = 0;
	mGammaPos[1] = 0;

	mColorGainLuma = 0;
	mColorGainPos[0] = 0;
	mColorGainPos[1] = 0;

	for ( int i = 0; i < IRIDAS_MODE_LAST; i++ )
	{
		for ( int j = 0; j < 3; j++ )
		{
			mOffsetXYZ[i][j] = 0;
			mGammaXYZ[i][j] = 0;
			mColorGainXYZ[i][j] = 0;
		}
		gIrex->SetLookVectorValue( 
			offsetStr[i], 
			mOffsetXYZ[i][0], 
			mOffsetXYZ[i][1], 
			mOffsetXYZ[i][2] 
		);
		gIrex->SetLookVectorValue( 
			gammaStr[i], 
			mGammaXYZ[i][0], 
			mGammaXYZ[i][1], 
			mGammaXYZ[i][2] 
		);
		gIrex->SetLookVectorValue( 
			colorGainStr[i], 
			mColorGainXYZ[i][0], 
			mColorGainXYZ[i][1], 
			mColorGainXYZ[i][2] 
		);

		for ( int j = 0; j < IRIDAS_SLIDER_LAST; j++ )
		{
			mSliderValues[j][i]= 0;
		}
	}
}


void CUIIridas::XyzToHsl( double *xyz, float &h, float &s, float &l )
{
	float r = ( (float) xyz[0] + 1 ) / 2;
	float g = ( (float) xyz[1] + 1 ) / 2;
	float b = ( (float) xyz[2] + 1 ) / 2;

	float v,m, vm, r2, g2, b2;

	h = 0; 
	s = 0;
    l = 0;

	v = max(r,g);
    v = max(v,b);
    m = min(r,g);
    m = min(m,b);

    l = (m + v) / 2.0f;
    if (l <= 0.0f)
    {
		return;
	}
    vm = v - m;
    s = vm;
    if (s > 0.0f)
	{
		s /= (l <= 0.5f) ? (v + m ) : (2.0f - v - m) ;
	}
	else
	{
		return;
	}

	r2 = (v - r) / vm;
	g2 = (v - g) / vm;
	b2 = (v - b) / vm;

	if (r == v)
	{
		h = (g == m ? 5.0f + b2 : 1.0f - g2);
	}

	else if (g == v)
	{
		h = (b == m ? 1.0f + r2 : 3.0f - b2);
	}

	else
	{
		h = (r == m ? 3.0f + g2 : 5.0f - r2);
	}
	h *= 60.0f;
}

void CUIIridas::RgbToHsl_VSCOPE( float *rgb, float &h, float &s, float &l )
{
	float v,m, vm, r2, g2, b2;

	h = 0; 
	s = 0;
    l = 0;

	v = max(rgb[0],rgb[1]);
    v = max(v,rgb[2]);
    m = min(rgb[0],rgb[1]);
    m = min(m,rgb[2]);

    // l = (m + v) / 2.0f;
    l = v;
    if (l <= 0.0f)
    {
		return;
	}

    vm = v - m;
    s = vm;
    if (s > 0.0f)
	{
		s /= (l <= 0.5f) ? (v + m ) : (2.0f - v - m) ;
	}
	else
	{
		return;
	}

	r2 = (v - rgb[0]) / vm;
	g2 = (v - rgb[1]) / vm;
	b2 = (v - rgb[2]) / vm;

	if (rgb[0] == v)
	{
		h = (rgb[1] == m ? 5.0f + b2 : 1.0f - g2);
	}

	else if (rgb[1] == v)
	{
		h = (rgb[2] == m ? 1.0f + r2 : 3.0f - b2);
	}

	else
	{
		h = (rgb[0] == m ? 3.0f + g2 : 5.0f - r2);
	}
	h *= 60.0f;
}

void CUIIridas::UpdateHSL( void )
{
	float h, s, l;

	// Offset
	XyzToHsl( mOffsetXYZ[mIridasMode], h, s, l );
	HsToXy( h, s, mOffsetPos[0], mOffsetPos[1] );
	mOffsetLuma = l*2.0f-1.0f;

	// Gamma
	double xyz[3];
	xyz[0] = -mGammaXYZ[mIridasMode][0];
	xyz[1] = -mGammaXYZ[mIridasMode][1];
	xyz[2] = -mGammaXYZ[mIridasMode][2];
	XyzToHsl( xyz, h, s, l );
	HsToXy( h, s, mGammaPos[0], mGammaPos[1] );
	mGammaLuma = l*2.0f-1.0f;

	// ColorGain
	XyzToHsl( mColorGainXYZ[mIridasMode], h, s, l );
	HsToXy( h, s, mColorGainPos[0], mColorGainPos[1] );
	mColorGainLuma = l*2.0f-1.0f;

}


void CUIIridas::HsToXy( float h, float s, float &x, float &y )
{
	float r = s * (float)IRI_CWHEEL_RADIUS;

	float angle = h * PI / 180.0f;
	x = -sin(angle) * r;
	y = -cos(angle) * r;
}



void CUIIridas::Load( char *filename )
{
	// Load look file
	//
	char lookpath[256];
	strcpy(lookpath,Globals.GetSIDir());
	strcat(lookpath,filename);

	IRBOOL loaded = gIrex->bLoadLook( lookpath );
	if ( !loaded )
	{
		return;
	}

	// OFFSET
	//
	gIrex->ReadLookVectorValue( 
		"offset", 
		&mOffsetXYZ[IRIDAS_MODE_OVERALL][0],
		&mOffsetXYZ[IRIDAS_MODE_OVERALL][1],
		&mOffsetXYZ[IRIDAS_MODE_OVERALL][2]
	);
	gIrex->ReadLookVectorValue( 
		"offsetHigh", 
		&mOffsetXYZ[IRIDAS_MODE_HIGHLIGHTS][0],
		&mOffsetXYZ[IRIDAS_MODE_HIGHLIGHTS][1],
		&mOffsetXYZ[IRIDAS_MODE_HIGHLIGHTS][2]
	);
	gIrex->ReadLookVectorValue( 
		"offsetMid", 
		&mOffsetXYZ[IRIDAS_MODE_MIDTONES][0],
		&mOffsetXYZ[IRIDAS_MODE_MIDTONES][1],
		&mOffsetXYZ[IRIDAS_MODE_MIDTONES][2]
	);
	gIrex->ReadLookVectorValue( 
		"offsetLow", 
		&mOffsetXYZ[IRIDAS_MODE_SHADOWS][0],
		&mOffsetXYZ[IRIDAS_MODE_SHADOWS][1],
		&mOffsetXYZ[IRIDAS_MODE_SHADOWS][2]
	);

	// GAMMA
	//
	gIrex->ReadLookVectorValue( 
		"gamma", 
		&mGammaXYZ[IRIDAS_MODE_OVERALL][0],
		&mGammaXYZ[IRIDAS_MODE_OVERALL][1],
		&mGammaXYZ[IRIDAS_MODE_OVERALL][2]
	);
	gIrex->ReadLookVectorValue( 
		"gammaHigh", 
		&mGammaXYZ[IRIDAS_MODE_HIGHLIGHTS][0],
		&mGammaXYZ[IRIDAS_MODE_HIGHLIGHTS][1],
		&mGammaXYZ[IRIDAS_MODE_HIGHLIGHTS][2]
	);
	gIrex->ReadLookVectorValue( 
		"gammaMid", 
		&mGammaXYZ[IRIDAS_MODE_MIDTONES][0],
		&mGammaXYZ[IRIDAS_MODE_MIDTONES][1],
		&mGammaXYZ[IRIDAS_MODE_MIDTONES][2]
	);
	gIrex->ReadLookVectorValue( 
		"gammaLow", 
		&mGammaXYZ[IRIDAS_MODE_SHADOWS][0],
		&mGammaXYZ[IRIDAS_MODE_SHADOWS][1],
		&mGammaXYZ[IRIDAS_MODE_SHADOWS][2]
	);

	// COLOR GAIN
	//
	gIrex->ReadLookVectorValue( 
		"gain", 
		&mColorGainXYZ[IRIDAS_MODE_OVERALL][0],
		&mColorGainXYZ[IRIDAS_MODE_OVERALL][1],
		&mColorGainXYZ[IRIDAS_MODE_OVERALL][2]
	);
	gIrex->ReadLookVectorValue( 
		"gainHigh", 
		&mColorGainXYZ[IRIDAS_MODE_HIGHLIGHTS][0],
		&mColorGainXYZ[IRIDAS_MODE_HIGHLIGHTS][1],
		&mColorGainXYZ[IRIDAS_MODE_HIGHLIGHTS][2]
	);
	gIrex->ReadLookVectorValue( 
		"gainMid", 
		&mColorGainXYZ[IRIDAS_MODE_MIDTONES][0],
		&mColorGainXYZ[IRIDAS_MODE_MIDTONES][1],
		&mColorGainXYZ[IRIDAS_MODE_MIDTONES][2]
	);
	gIrex->ReadLookVectorValue( 
		"gainLow", 
		&mColorGainXYZ[IRIDAS_MODE_SHADOWS][0],
		&mColorGainXYZ[IRIDAS_MODE_SHADOWS][1],
		&mColorGainXYZ[IRIDAS_MODE_SHADOWS][2]
	);


	for ( int j = 0; j < IRIDAS_SLIDER_LAST; j++ )
	{
		for ( int i = 0; i < IRIDAS_MODE_LAST; i++ )
		{
			mSliderValues[j][i] = gIrex->dReadLookScalarValue( 
				sliderStr[j][i]	);
		}
	}


	// load AlphaKeyerRGB

	char shaderName[256];
	unsigned int shaderNameLength;
	unsigned int numLayers = gIrex->nGetLookLayerCount();
	bool res;

	for ( unsigned int i = 0; i < numLayers; i++ )
	{
		res = gIrex->bGetLookShaderName( i, shaderName, &shaderNameLength );
		if ( !strcmp( shaderName, "fxKeyer" ) )
		{
			sprintf(mKeyerInfo.mColorName,"%d.screenColor",i);
			mKeyerInfo.mColor = gIrex->dReadLookScalarValue( mKeyerInfo.mColorName );
			Globals.mIridasVector[0] = (float) mKeyerInfo.mColor;

			sprintf(mKeyerInfo.mScaleName,"%d.scaleToOne",i);
			mKeyerInfo.mScale = gIrex->dReadLookScalarValue( mKeyerInfo.mScaleName	);
			if ( mKeyerInfo.mScale <= IRI_THRESHOLD_MIN ) mKeyerInfo.mScale = IRI_THRESHOLD_MIN;
			Globals.mIridasVector[1] = (float) ( 1.0 / mKeyerInfo.mScale );

			mKeyerInfo.mExists = true;
		}
	}

	if ( mKeyerInfo.mExists )
	{
		mKeyerMode = IRIDAS_KEYERMODE_COMP;
		mForeground->SetHighlight( false );
		mComposite->SetHighlight( true );
	}
	else
	{
		mKeyerMode = IRIDAS_KEYERMODE_FG;
		mForeground->SetHighlight( true );
		mComposite->SetHighlight( false );
	}
	mAlpha->SetHighlight( false );
	mBackground->SetHighlight( false );

	// Reload original look file
	gLut3d.LoadLook( mActiveLook, filename );
	gD3D->SetLut3DTextures();

	// Update look file names
	if ( ( gLookDialog ) && ( mActiveLook < 4 ) )
	{
		gLookDialog->UpdateLookNames();
	}
}


void CUIIridas::AddButton( CUIButton *button, int list )
{
	if ( list == 0 )
	{
		button->SetNext( mSet1List );
		mSet1List = button;
	}
	else if ( list == 1 )
	{
		button->SetNext( mSet2List );
		mSet2List = button;
	}
	else if ( list == 2 )
	{
		button->SetNext( mSet3List );
		mSet3List = button;
	}
	else 
	{
		button->SetNext( mSet1List );
		mSet1List = button;
		button->SetNext( mSet2List );
		mSet2List = button;
		button->SetNext( mSet3List );
		mSet3List = button;
	}
}

void CUIIridas::Init( void )
{
	float x = IRI_BUTTON_X * Globals.mMiniGuiMag;
	float y = IRI_BUTTON_Y * Globals.mMiniGuiMag;
	float w = IRI_BUTTON_W;
	float h = IRI_BUTTON_H;

	gD3D->SetFontSize( 18 );
	mControlSet1 = new CUITextButton(x,y,w,h,UIIRIDAS_CONTROL_SET1,NULL);
	mControlSet1->SetText( "CONTROL SET 1" );
	mControlSet1->SetHighlight( true );
	mControlSet1->SetRGBA( 120,120,120,255);
	AddButton( mControlSet1, -1 );

	y += IRI_BUTTON_DY;
	mControlSet2 = new CUITextButton(x,y,w,h,UIIRIDAS_CONTROL_SET2,NULL);
	mControlSet2->SetText( "CONTROL SET 2" );
	mControlSet2->SetRGBA( 120,120,120,255);
	AddButton( mControlSet2, -1 );

	y += IRI_BUTTON_DY;
	mKeyer = new CUITextButton(x,y,w,h,UIIRIDAS_KEYER,NULL);
	mKeyer->SetText( "KEYER" );
	mKeyer->SetRGBA( 120,120,120,255);
	AddButton( mKeyer, -1 );

	y += IRI_BUTTON_DY + 10;
	CUITextButton *tbutton = new CUITextButton( x, y, w, h, UIIRIDAS_LOAD_LOOK, NULL );
	tbutton->SetText( "LOAD LOOK" );
	tbutton->SetRGBA( 120, 120, 120, 255 );
	AddButton( tbutton, -1 );

	x = IRI_RBUTTON_X;
	y = IRI_BUTTON_Y;

	mOverall = new CUITextButton(x,y,w,h,UIIRIDAS_OVERALL,NULL);
	mOverall->SetText( "OVERALL" );
	mOverall->SetRGBA( 120,120,120,255);
	mOverall->SetHighlight( true );
	AddButton( mOverall, -1 );
	
	y += IRI_BUTTON_DY;
	mHighlights = new CUITextButton(x,y,w,h,UIIRIDAS_HIGHLIGHTS,NULL);
	mHighlights->SetText( "HIGHLIGHTS" );
	mHighlights->SetRGBA( 120,120,120,255);
	AddButton( mHighlights, -1 );

	y += IRI_BUTTON_DY;
	mMidtones = new CUITextButton(x,y,w,h,UIIRIDAS_MIDTONES,NULL);
	mMidtones->SetText( "MIDTONES" );
	mMidtones->SetRGBA( 120,120,120,255);
	AddButton( mMidtones, -1 );

	y += IRI_BUTTON_DY;
	mShadows = new CUITextButton(x,y,w,h,UIIRIDAS_SHADOWS,NULL);
	mShadows->SetText( "SHADOWS" );
	mShadows->SetRGBA( 120,120,120,255);
	AddButton( mShadows, -1 );

	y += IRI_BUTTON_DY + 10;
	tbutton = new CUITextButton(x,y,w,h,UIIRIDAS_RESET,NULL);
	tbutton->SetText( "RESET" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, -1 );

	y += IRI_BUTTON_DY + 50;
	tbutton = new CUITextButton( x, y, w ,h, UIIRIDAS_SAVE, NULL );
	tbutton->SetText( "SAVE LOOK" );
	tbutton->SetRGBA( 120, 120, 120, 255 );
	AddButton( tbutton, -1 );

	y += IRI_BUTTON_DY;
	tbutton = new CUITextButton( x, y, w, h, UIIRIDAS_DONE, NULL );
	tbutton->SetText( "DONE" );
	tbutton->SetRGBA( 120, 120, 120, 255 );
	AddButton( tbutton, -1 );

	CUIHotSpotButton *hbutton = new CUIHotSpotButton(
		IRI_HIST_X,
		IRI_HIST_Y,
		IRI_HIST_W,
		IRI_HIST_H,
		UIIRIDAS_HISTOGRAM,
		NULL
	);
	hbutton->SetRenderable(false);
	AddButton( hbutton, -1 );

	mHistogramButton = new CUITextButton(
		IRI_HIST_X,
		IRI_HIST_Y,
		IRI_HIST_W,
		IRI_HIST_H,
		UIIRIDAS_HISTOGRAM,
		NULL
	);
	mHistogramButton->SetText( "" );
	mHistogramButton->SetRGBA( 255,255,255,255);

	CUIImageIridasButton *ibutton = new CUIImageIridasButton(
		IRI_VIDEO_X,
		IRI_VIDEO_Y,
		IRI_VIDEO_W,
		IRI_VIDEO_H,
		-1,
		NULL
	);
	ibutton->SetRGBA( 68,68,68,255);
	AddButton( ibutton, -1 );


	x = IRI_INC_X1;
	y = IRI_INC_Y;
	w = IRI_INC_W;
	h = IRI_INC_H;
	tbutton = new CUITextButton(x,y,w,h,UIIRIDAS_OFFSET_PLUS,NULL);
	tbutton->SetText( "+" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 0 );

	tbutton = new CUITextButton(x,y+IRI_INC_DY,w,h,UIIRIDAS_OFFSET_MINUS,NULL);
	tbutton->SetText( "-" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 0 );

	hbutton = new CUIHotSpotButton(IRI_RAMP_X1,IRI_RAMP_Y,IRI_RAMP_W,IRI_RAMP_H,UIIRIDAS_OFFSET_BAR,NULL);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 0 );

	x = IRI_INC_X2;
	tbutton = new CUITextButton(x,y,w,h,UIIRIDAS_GAMMA_PLUS,NULL);
	tbutton->SetText( "+" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 0 );

	tbutton = new CUITextButton(x,y+IRI_INC_DY,w,h,UIIRIDAS_GAMMA_MINUS,NULL);
	tbutton->SetText( "-" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 0 );

	hbutton = new CUIHotSpotButton(IRI_RAMP_X2,IRI_RAMP_Y,IRI_RAMP_W,IRI_RAMP_H,UIIRIDAS_GAMMA_BAR,NULL);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 0 );

	x = IRI_INC_X3;
	tbutton = new CUITextButton(x,y,w,h,UIIRIDAS_COLORGAIN_PLUS,NULL);
	tbutton->SetText( "+" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 0 );

	tbutton = new CUITextButton(x,y+IRI_INC_DY,w,h,UIIRIDAS_COLORGAIN_MINUS,NULL);
	tbutton->SetText( "-" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 0 );

	hbutton = new CUIHotSpotButton(IRI_RAMP_X3,IRI_RAMP_Y,IRI_RAMP_W,IRI_RAMP_H,UIIRIDAS_COLORGAIN_BAR,NULL);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 0 );

	hbutton = new CUIHotSpotButton(
		IRI_GADGET_X1 - IRI_CWHEEL_W/2,
		IRI_GADGET_Y - IRI_CWHEEL_H/2,
		IRI_CWHEEL_W,
		IRI_CWHEEL_H,
		UIIRIDAS_OFFSET_CWHEEL,
		NULL
	);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 0 );

	hbutton = new CUIHotSpotButton(
		IRI_GADGET_X2 - IRI_CWHEEL_W/2,
		IRI_GADGET_Y - IRI_CWHEEL_H/2,
		IRI_CWHEEL_W,
		IRI_CWHEEL_H,
		UIIRIDAS_GAMMA_CWHEEL,
		NULL
	);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 0 );

	hbutton = new CUIHotSpotButton(
		IRI_GADGET_X3 - IRI_CWHEEL_W/2,
		IRI_GADGET_Y - IRI_CWHEEL_H/2,
		IRI_CWHEEL_W,
		IRI_CWHEEL_H,
		UIIRIDAS_COLORGAIN_CWHEEL,
		NULL
	);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 0 );



	//
	// SCREEN 2 buttons
	//


	x = IRI_SAT_X;
	y = IRI_SAT_Y;
	w = IRI_SAT_W;
	h = IRI_SAT_H;
	tbutton = new CUITextButton(x,y,w,h,UIIRIDAS_SAT_MINUS,NULL);
	tbutton->SetText( "-" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 1 );

	tbutton = new CUITextButton(x+IRI_SAT_DX,y,w,h,UIIRIDAS_SAT_PLUS,NULL);
	tbutton->SetText( "+" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 1 );

	hbutton = new CUIHotSpotButton(
		IRI_SAT_RAMP_X,
		IRI_SAT_RAMP_Y,
		IRI_SAT_RAMP_W,
		IRI_SAT_RAMP_H,
		UIIRIDAS_SAT_BAR, NULL);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 1 );

	y += IRI_SAT_DY;
	tbutton = new CUITextButton(x,y,w,h,UIIRIDAS_PIVOT_MINUS,NULL);
	tbutton->SetText( "-" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 1 );

	tbutton = new CUITextButton(x+IRI_SAT_DX,y,w,h,UIIRIDAS_PIVOT_PLUS,NULL);
	tbutton->SetText( "+" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 1 );

	hbutton = new CUIHotSpotButton(
		IRI_SAT_RAMP_X,
		IRI_SAT_RAMP_Y+IRI_SAT_DY,
		IRI_SAT_RAMP_W,
		IRI_SAT_RAMP_H,
		UIIRIDAS_PIVOT_BAR, NULL);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 1 );

	y += IRI_SAT_DY;
	tbutton = new CUITextButton(x,y,w,h,UIIRIDAS_TEMP_MINUS,NULL);
	tbutton->SetText( "-" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 1 );

	tbutton = new CUITextButton(x+IRI_SAT_DX,y,w,h,UIIRIDAS_TEMP_PLUS,NULL);
	tbutton->SetText( "+" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 1 );

	hbutton = new CUIHotSpotButton(
		IRI_SAT_RAMP_X,
		IRI_SAT_RAMP_Y+IRI_SAT_DY*2,
		IRI_SAT_RAMP_W,
		IRI_SAT_RAMP_H,
		UIIRIDAS_TEMP_BAR, NULL);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 1 );

	x = IRI_SAT_X + IRI_SAT_DX2;
	y = IRI_SAT_Y;
	tbutton = new CUITextButton(x,y,w,h,UIIRIDAS_GAIN_MINUS,NULL);
	tbutton->SetText( "-" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 1 );

	tbutton = new CUITextButton(x+IRI_SAT_DX,y,w,h,UIIRIDAS_GAIN_PLUS,NULL);
	tbutton->SetText( "+" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 1 );

	hbutton = new CUIHotSpotButton(
		IRI_SAT_RAMP_X+IRI_SAT_DX2,
		IRI_SAT_RAMP_Y,
		IRI_SAT_RAMP_W,
		IRI_SAT_RAMP_H,
		UIIRIDAS_GAIN_BAR, NULL);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 1 );

	y += IRI_SAT_DY;
	tbutton = new CUITextButton(x,y,w,h,UIIRIDAS_CONT_MINUS,NULL);
	tbutton->SetText( "-" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 1 );

	tbutton = new CUITextButton(x+IRI_SAT_DX,y,w,h,UIIRIDAS_CONT_PLUS,NULL);
	tbutton->SetText( "+" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 1 );

	hbutton = new CUIHotSpotButton(
		IRI_SAT_RAMP_X+IRI_SAT_DX2,
		IRI_SAT_RAMP_Y+IRI_SAT_DY,
		IRI_SAT_RAMP_W,
		IRI_SAT_RAMP_H,
		UIIRIDAS_CONT_BAR, NULL);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 1 );

	y += IRI_SAT_DY;
	tbutton = new CUITextButton(x,y,w,h,UIIRIDAS_MAG_MINUS,NULL);
	tbutton->SetText( "-" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 1 );

	tbutton = new CUITextButton(x+IRI_SAT_DX,y,w,h,UIIRIDAS_MAG_PLUS,NULL);
	tbutton->SetText( "+" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 1 );

	hbutton = new CUIHotSpotButton(
		IRI_SAT_RAMP_X+IRI_SAT_DX2,
		IRI_SAT_RAMP_Y+IRI_SAT_DY*2,
		IRI_SAT_RAMP_W,
		IRI_SAT_RAMP_H,
		UIIRIDAS_MAG_BAR, NULL);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 1 );

	//
	// KEYER buttons
	//


	x = 580;
	y = 506;
	tbutton = new CUITextButton(x,y,w,h,UIIRIDAS_THRESHOLD_MINUS,NULL);
	tbutton->SetText( "-" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 2 );

	tbutton = new CUITextButton(x+IRI_SAT_DX,y,w,h,UIIRIDAS_THRESHOLD_PLUS,NULL);
	tbutton->SetText( "+" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 2 );

	hbutton = new CUIHotSpotButton(
		x + 74,
		y + 8,
		IRI_SAT_RAMP_W,
		IRI_SAT_RAMP_H,
		UIIRIDAS_THRESHOLD_BAR, NULL);
	hbutton->SetRenderable(false);
	AddButton( hbutton, 2 );

	x = 215;
	y = 583;
	w = IRI_BUTTON_W;
	h = IRI_BUTTON_H;
	int g = 7;


	mGreen = new CUITextButton(x,y,w,h,UIIRIDAS_GREEN,NULL);
	mGreen->SetText( "GREEN" );
	mGreen->SetRGBA( 120,120,120,255);
	mGreen->SetHighlight( true );
	AddButton( mGreen, 2 );

	x += IRI_BUTTON_W + g;
	mGreyMatte = new CUITextButton(x,y,w,h,UIIRIDAS_GREYMATTE,NULL);
	mGreyMatte->SetText( "GREY MATTE" );
	mGreyMatte->SetHighlight( true );
	mGreyMatte->SetRGBA( 120,120,120,255);
	AddButton( mGreyMatte, 2 );

	x += IRI_BUTTON_W + g;
	mForeground = new CUITextButton(x,y,w,h,UIIRIDAS_FOREGROUND,NULL);
	mForeground->SetText( "FOREGROUND" );
	mForeground->SetRGBA( 120,120,120,255);
	mForeground->SetHighlight( true );
	AddButton( mForeground, 2 );

	x += IRI_BUTTON_W + g;
	mComposite = new CUITextButton(x,y,w,h,UIIRIDAS_COMPOSITE,NULL);
	mComposite->SetText( "COMPOSITE" );
	mComposite->SetRGBA( 120,120,120,255);
	AddButton( mComposite, 2 );

	x = 215;
	y += IRI_BUTTON_H + 4;
	mBlue = new CUITextButton(x,y,w,h,UIIRIDAS_BLUE,NULL);
	mBlue->SetText( "BLUE" );
	mBlue->SetRGBA( 120,120,120,255);
	mBlue->SetHighlight( false );
	AddButton( mBlue, 2 );


	x += IRI_BUTTON_W + g;
	tbutton = new CUITextButton(x,y,w,h,UIIRIDAS_LOADMATTE,OnLoadFrame);
	tbutton->SetText( "LOAD MATTE", "IMAGE" );
	tbutton->SetRGBA( 120,120,120,255);
	AddButton( tbutton, 2 );

	x += IRI_BUTTON_W + g;
	mBackground = new CUITextButton(x,y,w,h,UIIRIDAS_BACKGROUND,NULL);
	mBackground->SetText( "BACKGROUND" );
	mBackground->SetRGBA( 120,120,120,255);
	AddButton( mBackground, 2 );

	x += IRI_BUTTON_W + g;
	mAlpha = new CUITextButton(x,y,w,h,UIIRIDAS_ALPHA,NULL);
	mAlpha->SetText( "ALPHA" );
	mAlpha->SetRGBA( 120,120,120,255);
	AddButton( mAlpha, 2 );

}


double GetHueRangePart( double hueRange )
{
	double part = (hueRange-IRI_HUERANGE_MIN) / (IRI_HUERANGE_MAX-IRI_HUERANGE_MIN);
	return part;
}

double GetLumaRangePart( double lumaRange )
{
	double part = (lumaRange-IRI_LUMARANGE_MIN) / (IRI_LUMARANGE_MAX-IRI_LUMARANGE_MIN);
	return part;
}


void CUIIridas::Render( void )
{

	CUIButton *button = NULL;
	if ( mSet == 0 ) 
		button = mSet1List;
	else if ( mSet == 1 ) 
		button = mSet2List;
	else 
		button = mSet3List;

	RenderDialogButtons( button );

	if ( !gPrefs.GetMode800() )
		gD3D->SetPointFilter( true );

	if ( mHistogramMode )
	{
		mHistogram.Render();
	}
	else
	{
		gD3D->RenderVScope();
		mVScope.Render();
	}

	if ( mSet == 0 )
	{
		gColorQuad.mVertices[0].color = 0x00ffffff;
		gColorQuad.mVertices[1].color = 0x00ffffff;
		gColorQuad.mVertices[2].color = 0;
		gColorQuad.mVertices[3].color = 0;

		gColorQuad.SetVertexScale( IRI_RAMP_X1, IRI_RAMP_Y );
		gColorQuad.SetVertexScale( IRI_RAMP_X1+IRI_RAMP_W, IRI_RAMP_Y );
		gColorQuad.SetVertexScale( IRI_RAMP_X1, IRI_RAMP_Y+IRI_RAMP_H );
		gColorQuad.SetVertexScale( IRI_RAMP_X1+IRI_RAMP_W, IRI_RAMP_Y+IRI_RAMP_H );

		gColorQuad.SetVertexScale( IRI_RAMP_X2, IRI_RAMP_Y );
		gColorQuad.SetVertexScale( IRI_RAMP_X2+IRI_RAMP_W, IRI_RAMP_Y );
		gColorQuad.SetVertexScale( IRI_RAMP_X2, IRI_RAMP_Y+IRI_RAMP_H );
		gColorQuad.SetVertexScale( IRI_RAMP_X2+IRI_RAMP_W, IRI_RAMP_Y+IRI_RAMP_H );

		gColorQuad.SetVertexScale( IRI_RAMP_X3, IRI_RAMP_Y );
		gColorQuad.SetVertexScale( IRI_RAMP_X3+IRI_RAMP_W, IRI_RAMP_Y );
		gColorQuad.SetVertexScale( IRI_RAMP_X3, IRI_RAMP_Y+IRI_RAMP_H );
		gColorQuad.SetVertexScale( IRI_RAMP_X3+IRI_RAMP_W, IRI_RAMP_Y+IRI_RAMP_H );

		float cx,cy;
		cx = IRI_RAMP_X2 + IRI_RAMP_W/2;
		cy = IRI_RAMP_Y + IRI_RAMP_H/2 - ( int ) ( mGammaLuma * IRI_RAMP_H / 2 );
		DrawBracket( cx, cy, false );

		cx = IRI_RAMP_X1 + IRI_RAMP_W/2;
		cy = IRI_RAMP_Y + IRI_RAMP_H/2 - ( int ) ( mOffsetLuma * IRI_RAMP_H / 2 );
		DrawBracket( cx, cy, false );

		cx = IRI_RAMP_X3 + IRI_RAMP_W/2;
		cy = IRI_RAMP_Y + IRI_RAMP_H/2 - ( int ) ( mColorGainLuma * IRI_RAMP_H / 2 );
		DrawBracket( cx, cy, false );

		gD3D->RenderCWheel();

		DrawCWheelBox( 
			(float) IRI_GADGET_X1 + mOffsetPos[0], 
			(float) IRI_GADGET_Y + mOffsetPos[1] 
		);

		DrawCWheelBox( 
			(float) IRI_GADGET_X2 + mGammaPos[0], 
			(float) IRI_GADGET_Y + mGammaPos[1] 
		);

		DrawCWheelBox( 
			(float) IRI_GADGET_X3 + mColorGainPos[0], 
			(float) IRI_GADGET_Y + mColorGainPos[1] 
		);

		GIGE_STRINGOUT( 27, 501, "OFFSET" );
		GIGE_STRINGOUT( 446, 501, "GAMMA" );
		GIGE_STRINGOUT( 845, 501, "COLOR GAIN" );
	}
	else if ( mSet == 1 )
	{
		DWORD color1;
		DWORD color2;
		float x,y,w,h,cx,cy;

		// Saturation gadget
		//
		color1 = 0;
		color2 = 0x00ffffff;
		gColorQuad.mVertices[0].color = color1;
		gColorQuad.mVertices[1].color = color2;
		gColorQuad.mVertices[2].color = color1;
		gColorQuad.mVertices[3].color = color2;

		x = IRI_SAT_RAMP_X;
		y = IRI_SAT_RAMP_Y;
		w = IRI_SAT_RAMP_W;
		h = IRI_SAT_RAMP_H;
		gColorQuad.SetVertexScale(   x,  y );
		gColorQuad.SetVertexScale( x+w,   y );
		gColorQuad.SetVertexScale(   x, y+h );
		gColorQuad.SetVertexScale( x+w, y+h );

		cx = x + w/2 + ( int ) ( ( mSliderValues[IRIDAS_SLIDER_SAT][mIridasMode] - 1 )  * (float) w / 2.0f ) ;
		cy = y + h/2;
		DrawBracket( cx, cy, true );

		GIGE_STRINGOUTRIGHT( x - 85, y, "SATURATION" );


		// Pivot gadget
		y += IRI_SAT_DY;
		color1 = 0;
		color2 = 0x00ffffff;
		gColorQuad.mVertices[0].color = color1;
		gColorQuad.mVertices[1].color = color2;
		gColorQuad.mVertices[2].color = color1;
		gColorQuad.mVertices[3].color = color2;
		gColorQuad.SetVertexScale(   x,  y );
		gColorQuad.SetVertexScale( x+w,   y );
		gColorQuad.SetVertexScale(   x, y+h );
		gColorQuad.SetVertexScale( x+w, y+h );
		cx = x + w/2 + ( int ) ( ( mSliderValues[IRIDAS_SLIDER_PIVOT][mIridasMode] - 0.5 ) * (float) w ) ;
		cy = y + h/2;
		DrawBracket( cx, cy, true );
	
		GIGE_STRINGOUTRIGHT( x - 85, y, "CONTRAST PIVOT" );


		// Temperature gadget
		y += IRI_SAT_DY;
		// blue
		color1 = 0x000000ff;
		// orange
		color2 = 0x00ffa000;
		gColorQuad.mVertices[0].color = color1;
		gColorQuad.mVertices[1].color = color2;
		gColorQuad.mVertices[2].color = color1;
		gColorQuad.mVertices[3].color = color2;
		gColorQuad.SetVertexScale(   x,  y );
		gColorQuad.SetVertexScale( x+w,   y );
		gColorQuad.SetVertexScale(   x, y+h );
		gColorQuad.SetVertexScale( x+w, y+h );
		cx = x + w/2 + ( int ) ( mSliderValues[IRIDAS_SLIDER_TEMP][mIridasMode] * (float) w / 2.0f ) ;
		cy = y + h/2;
		DrawBracket( cx, cy, true );
		
		GIGE_STRINGOUTRIGHT( x - 85, y, "TEMPERATURE" );

		x += 454;
		y = IRI_SAT_RAMP_Y;

		// Overall Gain gadget
		color1 = 0;
		color2 = 0x00ffffff;
		gColorQuad.mVertices[0].color = color1;
		gColorQuad.mVertices[1].color = color2;
		gColorQuad.mVertices[2].color = color1;
		gColorQuad.mVertices[3].color = color2;

		gColorQuad.SetVertexScale(   x,  y );
		gColorQuad.SetVertexScale( x+w,   y );
		gColorQuad.SetVertexScale(   x, y+h );
		gColorQuad.SetVertexScale( x+w, y+h );
		cx = x + w/2 + ( int ) ( mSliderValues[IRIDAS_SLIDER_OVERALL][mIridasMode] * (float) w / 2.0f ) ;
		cy = y + h/2;
		DrawBracket( cx, cy, true );
		GIGE_STRINGOUT( x + 220, y, "OVERALL GAIN" );

		// Contrast gadget
		y += IRI_SAT_DY;
		color1 = 0;
		color2 = 0x00ffffff;
		gColorQuad.mVertices[0].color = color1;
		gColorQuad.mVertices[1].color = color2;
		gColorQuad.mVertices[2].color = color1;
		gColorQuad.mVertices[3].color = color2;
		gColorQuad.SetVertexScale(   x,  y );
		gColorQuad.SetVertexScale( x+w,   y );
		gColorQuad.SetVertexScale(   x, y+h );
		gColorQuad.SetVertexScale( x+w, y+h );
		cx = x + w/2 + ( int ) ( mSliderValues[IRIDAS_SLIDER_CONTRAST][mIridasMode] * (float) w / 2.0f ) ;
		cy = y + h/2;
		DrawBracket( cx, cy, true );
		GIGE_STRINGOUT( x + 220, y, "CONTRAST" );

		// Magenta/Green gadget
		y += IRI_SAT_DY;
		// magenta
		color2 = 0x00ff20ff;
		// green
		color1 = 0x0020a020;
		gColorQuad.mVertices[0].color = color1;
		gColorQuad.mVertices[1].color = color2;
		gColorQuad.mVertices[2].color = color1;
		gColorQuad.mVertices[3].color = color2;
		gColorQuad.SetVertexScale(   x,  y );
		gColorQuad.SetVertexScale( x+w,   y );
		gColorQuad.SetVertexScale(   x, y+h );
		gColorQuad.SetVertexScale( x+w, y+h );
		cx = x + w/2 + ( int ) ( mSliderValues[IRIDAS_SLIDER_MAGENTA][mIridasMode] * (float) w / 2.0f ) ;
		cy = y + h/2;
		DrawBracket( cx, cy, true );
		GIGE_STRINGOUT( x + 220, y, "MAGENTA/GREEN" );
	}
	else if ( mSet == 2 )
	{
		DWORD color1;
		DWORD color2;
		float x,y,w,h,cx,cy;

		// Treshold gadget
		x = 580 + 74;
		y = 506 + 8;
		w = IRI_SAT_RAMP_W;
		h = IRI_SAT_RAMP_H;
		color1 = 0;
		color2 = 0x00ffffff;
		gColorQuad.mVertices[0].color = color1;
		gColorQuad.mVertices[1].color = color2;
		gColorQuad.mVertices[2].color = color1;
		gColorQuad.mVertices[3].color = color2;
		gColorQuad.SetVertexScale(   x,  y );
		gColorQuad.SetVertexScale( x+w,   y );
		gColorQuad.SetVertexScale(   x, y+h );
		gColorQuad.SetVertexScale( x+w, y+h );
		cx = (float) ( x + (mKeyerInfo.mScale - IRI_THRESHOLD_MIN) / (IRI_THRESHOLD_MAX-IRI_HUERANGE_MIN) * (double) w ) ;
		cy = y + h/2;
		DrawBracket( cx, cy, true );
		GIGE_STRINGOUTRIGHT( x - 85, y, "THRESHOLD" );

	}

	gD3D->RenderILogo();
	gD3D->SetPointFilter( false );
	if ( mLookFileDialog )
	{
		mLookFileDialog->Render();
	}

	if ( gUIManager->mScreen->mMessageBox )
	{
		gUIManager->mScreen->mMessageBox->Render();
	}

	char str[256];
	if ( isProgramPlayingAVI() || isProgramPlayingSIV() )
		mActiveLook = gPrefs.GetPlayerLook();
	else if ( gPrefs.GetPreviewLookActive() )
		mActiveLook = gPrefs.GetViewLook();
	else
		mActiveLook = gPrefs.GetRecordLook();

	strcpy( str, "LOOK FILE: " );

	if ( mActiveLook < 4 )
	{
		strcat( str, gPrefs.GetLookName( mActiveLook ) );
	}
	else
	{
		strcat( str, mLoadLook );
	}
	GIGE_STRINGOUT( 240, 25, str );

	if ( gPrefs.GetDebugMode() )
	{
		sprintf(str, "KEYER: COLOR %04f THRESHOLD SAT %04f",mKeyerInfo.mColor, mKeyerInfo.mScale );
		GIGE_STRINGOUT( 240, 50, str );
		sprintf(str, "OFFSET %04f %04f %04f",mOffsetXYZ[mIridasMode][0], mOffsetXYZ[mIridasMode][1], mOffsetXYZ[mIridasMode][2] );
		GIGE_STRINGOUT( 240, 130, str );
		sprintf(str, "GAMMA %04f %04f %04f",mGammaXYZ[mIridasMode][0], mGammaXYZ[mIridasMode][1], mGammaXYZ[mIridasMode][2] );
		GIGE_STRINGOUT( 240, 170, str );
		sprintf(str, "GAIN %04f %04f %04f",mColorGainXYZ[mIridasMode][0], mColorGainXYZ[mIridasMode][1], mColorGainXYZ[mIridasMode][2] );
		GIGE_STRINGOUT( 240, 210, str );
	}
}


void CUIIridas::AddKeyerLayer( void )
{
	char str[32];
	unsigned int numLayers = gIrex->nGetLookLayerCount();
	IRBOOL res = gIrex->bInsertLookLayer( numLayers, "fxKeyer" );

	sprintf(mKeyerInfo.mColorName,"%d.screenColor",numLayers);
	gIrex->SetLookScalarValue( mKeyerInfo.mColorName, mKeyerInfo.mColor );
	sprintf(mKeyerInfo.mScaleName,"%d.scaleToOne",numLayers);
	gIrex->SetLookScalarValue( mKeyerInfo.mScaleName, mKeyerInfo.mScale );

	sprintf(str,"%d.remap",numLayers);
	gIrex->SetLookScalarValue( str, 0 );
	sprintf(str,"%d.showRange",numLayers);
	gIrex->SetLookScalarValue( str, 0 );

	Globals.mIridasVector[0] = (float) mKeyerInfo.mColor;
	if ( mKeyerInfo.mScale <= IRI_THRESHOLD_MIN ) 
	{
		mKeyerInfo.mScale = IRI_THRESHOLD_MIN;
	}
	Globals.mIridasVector[1] = (float) ( 1.0 / mKeyerInfo.mScale );

	mKeyerInfo.mExists = true;
}



void CUIIridas::OnClick( int x, int y )
{
	if ( mLookFileDialog )
	{
		mLookFileDialog->HandleClick( x, y );
		return;
	}
	
	if ( gUIManager->mScreen->mMessageBox )
	{
		gUIManager->mScreen->mMessageBox->HandleClick( x, y );
	}

	//buttons
	CUIButton *button = NULL;
	if ( mSet == 0 )
		button = mSet1List;
	else if ( mSet == 1 )
		button = mSet2List;
	else
		button = mSet3List;
	while ( button )
	{
		if ( button->HandleClick(x,y) ) 
			break;
		button = button->GetNext();
	}
	if ( !button ) return;

	if ( button->GetID() != UIIRIDAS_DONE )
	{
		mValChanged = true;
	}

	switch ( button->GetID() )
	{
	case UIIRIDAS_CONTROL_SET1:
		mSet = 0;
		mControlSet1->SetHighlight( true );
		mControlSet2->SetHighlight( false );
		mKeyer->SetHighlight( false );
		mOverall->SetActive( true );
		mHighlights->SetActive( true );
		mMidtones->SetActive( true );
		mShadows->SetActive( true );
		break;

	case UIIRIDAS_CONTROL_SET2:
		mSet = 1;
		mControlSet2->SetHighlight( true );
		mControlSet1->SetHighlight( false );
		mKeyer->SetHighlight( false );
		mOverall->SetActive( true );
		mHighlights->SetActive( true );
		mMidtones->SetActive( true );
		mShadows->SetActive( true );
		break;

	case UIIRIDAS_KEYER:
		if ( !mKeyerInfo.mExists )
		{
			AddKeyerLayer();
			AddKeyerLayer();
			mKeyerMode = IRIDAS_KEYERMODE_COMP;
			mForeground->SetHighlight( false );
			mComposite->SetHighlight( true );
		}
		mSet = 2;
		mControlSet2->SetHighlight( false );
		mControlSet1->SetHighlight( false );
		mKeyer->SetHighlight( true );
		mOverall->SetActive( false );
		mHighlights->SetActive( false );
		mMidtones->SetActive( false );
		mShadows->SetActive( false );
		if ( mKeyerInfo.mColor < 0 )
		{
			mGreen->SetHighlight( true );
			mBlue->SetHighlight( false );
		}
		else
		{
			mGreen->SetHighlight( false );
			mBlue->SetHighlight( true );
		}
		break;

	case UIIRIDAS_LOAD_LOOK:
		OpenFileDialog( FILE_TYPE_LOOK, mLoadLook );
		break;

	case UIIRIDAS_OVERALL:
		mIridasMode = IRIDAS_MODE_OVERALL;
		mOverall->SetHighlight( true );
		mHighlights->SetHighlight( false );
		mMidtones->SetHighlight( false );
		mShadows->SetHighlight( false );
		UpdateHSL();
		break;

	case UIIRIDAS_HIGHLIGHTS:
		mIridasMode = IRIDAS_MODE_HIGHLIGHTS;
		mOverall->SetHighlight( false );
		mHighlights->SetHighlight( true );
		mMidtones->SetHighlight( false );
		mShadows->SetHighlight( false );
		UpdateHSL();
		break;

	case UIIRIDAS_MIDTONES:
		mIridasMode = IRIDAS_MODE_MIDTONES;
		mOverall->SetHighlight( false );
		mHighlights->SetHighlight( false );
		mMidtones->SetHighlight( true );
		mShadows->SetHighlight( false );
		UpdateHSL();
		break;

	case UIIRIDAS_SHADOWS:
		mIridasMode = IRIDAS_MODE_SHADOWS;
		mOverall->SetHighlight( false );
		mHighlights->SetHighlight( false );
		mMidtones->SetHighlight( false );
		mShadows->SetHighlight( true );
		UpdateHSL();
		break;

	case UIIRIDAS_DONE:
		if ( mValChanged )
		{
			gUIScreen->SaveIridas();
		}
		else
		{
			Globals.SetPolledEvent( POLLED_EVENT_DELETEIRIDAS );
		}
		break;

	case UIIRIDAS_SAVE:
		OnSaveLookFile( 0, 0 );
		break;

	case UIIRIDAS_RESET:
		Load( mFilename );
		UpdateHSL();
		Update();
		break;

	case UIIRIDAS_HISTOGRAM:
		mHistogramMode ^= 1;
		Globals.SetUpdateIridasGraphs( true );
		break;

	case UIIRIDAS_OFFSET_PLUS:
		if ( Inc( &mOffsetLuma, 1, IRI_INCREMENT ) )
		{
			UpdateOffset();
			Update();
		}
		break;

	case UIIRIDAS_OFFSET_MINUS:
		if ( Dec( &mOffsetLuma, -1, IRI_INCREMENT ) )
		{
			UpdateOffset();
			Update();
		}
		break;

	case UIIRIDAS_GAMMA_PLUS:
		if ( Inc( &mGammaLuma, 1, IRI_INCREMENT ) )
		{
			UpdateGamma();
			Update();
		}
		break;

	case UIIRIDAS_GAMMA_MINUS:
		if ( Dec( &mGammaLuma, -1, IRI_INCREMENT ) )
		{
			UpdateGamma();
			Update();
		}
		break;

	case UIIRIDAS_COLORGAIN_PLUS:
		if ( Inc( &mColorGainLuma, 1, IRI_INCREMENT ) )
		{
			UpdateColorGain();
			Update();
		}
		break;

	case UIIRIDAS_COLORGAIN_MINUS:
		if ( Dec( &mColorGainLuma, -1, IRI_INCREMENT ) )
		{
			UpdateColorGain();
			Update();
		}
		break;

	case UIIRIDAS_SAT_PLUS:
		Inc( &mSliderValues[IRIDAS_SLIDER_SAT][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_SAT][2], IRI_INCREMENT );
		UpdateSliders(IRIDAS_SLIDER_SAT);
		Update();
		break;

	case UIIRIDAS_SAT_MINUS:
		Dec( &mSliderValues[IRIDAS_SLIDER_SAT][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_SAT][0], IRI_INCREMENT );
		UpdateSliders(IRIDAS_SLIDER_SAT);
		Update();
		break;

	case UIIRIDAS_PIVOT_PLUS:
		Inc( &mSliderValues[IRIDAS_SLIDER_PIVOT][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_PIVOT][2], IRI_INCREMENT );
		UpdateSliders(IRIDAS_SLIDER_PIVOT);
		Update();
		break;

	case UIIRIDAS_PIVOT_MINUS:
		Dec( &mSliderValues[IRIDAS_SLIDER_PIVOT][mIridasMode],
			sliderMinMidMax[IRIDAS_SLIDER_PIVOT][0], IRI_INCREMENT );
		UpdateSliders(IRIDAS_SLIDER_PIVOT);
		Update();
		break;

	case UIIRIDAS_TEMP_PLUS:
		Inc( &mSliderValues[IRIDAS_SLIDER_TEMP][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_TEMP][2], IRI_INCREMENT );
		UpdateSliders(IRIDAS_SLIDER_TEMP);
		Update();
		break;

	case UIIRIDAS_TEMP_MINUS:
		Dec( &mSliderValues[IRIDAS_SLIDER_TEMP][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_TEMP][0], IRI_INCREMENT );
		UpdateSliders(IRIDAS_SLIDER_TEMP);
		Update();
		break;

	case UIIRIDAS_GAIN_PLUS:
		Inc( &mSliderValues[IRIDAS_SLIDER_OVERALL][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_OVERALL][2], IRI_INCREMENT );
		UpdateSliders(IRIDAS_SLIDER_OVERALL);
		Update();
		break;

	case UIIRIDAS_GAIN_MINUS:
		Dec( &mSliderValues[IRIDAS_SLIDER_OVERALL][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_OVERALL][0], IRI_INCREMENT );
		UpdateSliders(IRIDAS_SLIDER_OVERALL);
		Update();
		break;

	case UIIRIDAS_CONT_PLUS:
		Inc( &mSliderValues[IRIDAS_SLIDER_CONTRAST][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_CONTRAST][2], IRI_INCREMENT );
		UpdateSliders(IRIDAS_SLIDER_CONTRAST);
		Update();
		break;

	case UIIRIDAS_CONT_MINUS:
		Dec( &mSliderValues[IRIDAS_SLIDER_CONTRAST][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_CONTRAST][0], IRI_INCREMENT );
		UpdateSliders(IRIDAS_SLIDER_CONTRAST);
		Update();
		break;

	case UIIRIDAS_MAG_PLUS:
		Inc( &mSliderValues[IRIDAS_SLIDER_MAGENTA][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_MAGENTA][2], IRI_INCREMENT );
		UpdateSliders(IRIDAS_SLIDER_MAGENTA);
		Update();
		break;

	case UIIRIDAS_MAG_MINUS:
		Dec( &mSliderValues[IRIDAS_SLIDER_MAGENTA][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_MAGENTA][0], IRI_INCREMENT );
		UpdateSliders(IRIDAS_SLIDER_MAGENTA);
		Update();
		break;

	case UIIRIDAS_OFFSET_CWHEEL:
		CWheelClick( UIIRIDAS_OFFSET_CWHEEL, x, y );
		UpdateOffset();
		Update();
		break;
	case UIIRIDAS_GAMMA_CWHEEL:
		CWheelClick( UIIRIDAS_GAMMA_CWHEEL, x, y );
		UpdateGamma();
		Update();
		break;
	case UIIRIDAS_COLORGAIN_CWHEEL:
		CWheelClick( UIIRIDAS_COLORGAIN_CWHEEL, x, y );
		UpdateColorGain();
		Update();
		break;

	case UIIRIDAS_FOREGROUND:
		mKeyerMode = IRIDAS_KEYERMODE_FG;
		mForeground->SetHighlight( true );
		mComposite->SetHighlight( false );
		mAlpha->SetHighlight( false );
		mBackground->SetHighlight( false );
		break;
	case UIIRIDAS_COMPOSITE:
		mKeyerMode = IRIDAS_KEYERMODE_COMP;
		mForeground->SetHighlight( false );
		mComposite->SetHighlight( true );
		mAlpha->SetHighlight( false );
		mBackground->SetHighlight( false );
		break;
	case UIIRIDAS_ALPHA:
		mKeyerMode = IRIDAS_KEYERMODE_A;
		mForeground->SetHighlight( false );
		mComposite->SetHighlight( false );
		mAlpha->SetHighlight( true );
		mBackground->SetHighlight( false );
		break;
	case UIIRIDAS_BACKGROUND:
		mKeyerMode = IRIDAS_KEYERMODE_BG;
		mForeground->SetHighlight( false );
		mComposite->SetHighlight( false );
		mAlpha->SetHighlight( false );
		mBackground->SetHighlight( true );
		break;

	case UIIRIDAS_THRESHOLD_PLUS:
		Inc( &mKeyerInfo.mScale, IRI_THRESHOLD_MAX, IRI_INCREMENT );
		gIrex->SetLookScalarValue( mKeyerInfo.mScaleName, mKeyerInfo.mScale );
		if ( mKeyerInfo.mScale <= IRI_THRESHOLD_MIN ) 
		{
			mKeyerInfo.mScale = IRI_THRESHOLD_MIN;
		}
		Globals.mIridasVector[1] = (float) ( 1.0 / mKeyerInfo.mScale );
		break;

	case UIIRIDAS_THRESHOLD_MINUS:
		Dec( &mKeyerInfo.mScale, IRI_THRESHOLD_MIN, IRI_INCREMENT );
		gIrex->SetLookScalarValue( mKeyerInfo.mScaleName, mKeyerInfo.mScale );
		if ( mKeyerInfo.mScale <= IRI_THRESHOLD_MIN ) 
		{
			mKeyerInfo.mScale = IRI_THRESHOLD_MIN;
		}
		Globals.mIridasVector[1] = (float) ( 1.0 / mKeyerInfo.mScale );
		break;

	case UIIRIDAS_GREEN:
		mKeyerInfo.mColor = -1;
		Globals.mIridasVector[0] = (float) mKeyerInfo.mColor;
		mGreen->SetHighlight( true );
		mBlue->SetHighlight( false );
		gIrex->SetLookScalarValue( mKeyerInfo.mColorName, mKeyerInfo.mColor );
		break;

	case UIIRIDAS_BLUE:
		mKeyerInfo.mColor = 1;
		Globals.mIridasVector[0] = (float) mKeyerInfo.mColor;
		mGreen->SetHighlight( false );
		mBlue->SetHighlight( true );
		gIrex->SetLookScalarValue( mKeyerInfo.mColorName, mKeyerInfo.mColor );
		break;

	case UIIRIDAS_GREYMATTE:
		mGreyOn ^= 1;
		if ( mGreyOn )
			mGreyMatte->SetHighlight( true );
		else
			mGreyMatte->SetHighlight( false );
		break;

	case UIIRIDAS_LOADMATTE:
		OnLoadFrame(0,0);
		break;

	}

	InvalidateRect( Globals.hwnd, NULL, false );
}


void RgbToHsl( float r, float g, float b, double &h, double &s, double &l )
{
	float v,m, vm, r2, g2, b2;

	h = 0; 
	s = 0;
    l = 0;

	v = max(r,g);
    v = max(v,b);
    m = min(r,g);
    m = min(m,b);

    l = (m + v) / 2.0f;
    if (l <= 0.0f)
    {
		return;
	}
    vm = v - m;
    s = vm;
    if (s > 0.0f)
	{
		s /= (l <= 0.5f) ? (v + m ) : (2.0f - v - m) ;
	}
	else
	{
		return;
	}

	r2 = (v - r) / vm;
	g2 = (v - g) / vm;
	b2 = (v - b) / vm;

	if (r == v)
	{
		h = (g == m ? 5.0f + b2 : 1.0f - g2);
	}

	else if (g == v)
	{
		h = (b == m ? 1.0f + r2 : 3.0f - b2);
	}

	else
	{
		h = (r == m ? 3.0f + g2 : 5.0f - r2);
	}
	h *= 60.0f;
}


void CUIIridas::UpdateGraphs( unsigned char *data, int width, int height )
{
	if ( mTrackballOn ) return;
	DWORD ticks = GetTickCount();
	if ( mHistogramMode )
		mHistogram.UpdateImage( data, width, height );
	else
		mVScope.UpdateImage( data, width, height );
	DWORD d = GetTickCount() - ticks;
}

void CUIIridas::Trilin( float r, float g, float b, float *pr, float *pg, float *pb )
{
	float *data = gLut3d.mIriData;

	int red_index0   = (int) ( r * (float) (IRI_SIZE-1) );
	int green_index0 = (int) ( g * (float) (IRI_SIZE-1) );
	int blue_index0  = (int) ( b * (float) (IRI_SIZE-1) );
	
	int red_index1   = red_index0 + 1;
	int green_index1 = green_index0 + 1;
	int blue_index1  = blue_index0 + 1;

	if ( red_index1 == IRI_SIZE ) red_index1--;
	if ( green_index1 == IRI_SIZE ) green_index1--;
	if ( blue_index1 == IRI_SIZE ) blue_index1--;

	float x = r * (float) (IRI_SIZE-1) - (float) red_index0;
	float y = g * (float) (IRI_SIZE-1) - (float) green_index0;
	float z = b * (float) (IRI_SIZE-1) - (float) blue_index0;
	float xm = 1.0f - x;
	float ym = 1.0f - y;
	float zm = 1.0f - z;

	float *V000 = &data[red_index0 * 3 + green_index0 * 3 * IRI_SIZE + blue_index0 * 3 * IRI_SIZE * IRI_SIZE];
	float *V001 = &data[red_index0 * 3 + green_index0 * 3 * IRI_SIZE + blue_index1 * 3 * IRI_SIZE * IRI_SIZE];
	float *V010 = &data[red_index0 * 3 + green_index1 * 3 * IRI_SIZE + blue_index0 * 3 * IRI_SIZE * IRI_SIZE];
	float *V011 = &data[red_index0 * 3 + green_index1 * 3 * IRI_SIZE + blue_index1 * 3 * IRI_SIZE * IRI_SIZE];
	float *V100 = &data[red_index1 * 3 + green_index0 * 3 * IRI_SIZE + blue_index0 * 3 * IRI_SIZE * IRI_SIZE];
	float *V101 = &data[red_index1 * 3 + green_index0 * 3 * IRI_SIZE + blue_index1 * 3 * IRI_SIZE * IRI_SIZE];
	float *V110 = &data[red_index1 * 3 + green_index1 * 3 * IRI_SIZE + blue_index0 * 3 * IRI_SIZE * IRI_SIZE];
	float *V111 = &data[red_index1 * 3 + green_index1 * 3 * IRI_SIZE + blue_index1 * 3 * IRI_SIZE * IRI_SIZE];
	float Vxyz[3];

	for ( int i = 0; i < 3; i++ )
	{
		Vxyz[i] = 	
			V000[i] * xm * ym * zm +
			V100[i] * x  * ym * zm +
			V010[i] * xm * y  * zm +
			V001[i] * xm * ym * z +
			V101[i] * x  * ym * z +
			V011[i] * xm * y  * z +
			V110[i] * x  * y  * zm +
			V111[i] * x  * y  * z;
	}

	*pr = Vxyz[0];
	*pg = Vxyz[1];
	*pb = Vxyz[2];

	if ( *pr > 1 ) *pr = 1;
	if ( *pr < 0 ) *pr = 0;
	if ( *pg > 1 ) *pg = 1;
	if ( *pg < 0 ) *pg = 0;
	if ( *pb > 1 ) *pb = 1;
	if ( *pb < 0 ) *pb = 0;

}


void CUIIridas::Trilin8( unsigned char r, unsigned char g, unsigned char b, float *rgb )
{
	float *data = gLut3d.mIriData;

	int red_index0   = (int) ( mLut8[r] * (float) (IRI_SIZE-1) );
	int green_index0 = (int) ( mLut8[g] * (float) (IRI_SIZE-1) );
	int blue_index0  = (int) ( mLut8[b] * (float) (IRI_SIZE-1) );
	
	int red_index1   = red_index0 + 1;
	int green_index1 = green_index0 + 1;
	int blue_index1  = blue_index0 + 1;

	if ( red_index1 == IRI_SIZE ) red_index1--;
	if ( green_index1 == IRI_SIZE ) green_index1--;
	if ( blue_index1 == IRI_SIZE ) blue_index1--;

	float x = mLut8[r] * (float) (IRI_SIZE-1) - (float) red_index0;
	float y = mLut8[g] * (float) (IRI_SIZE-1) - (float) green_index0;
	float z = mLut8[b] * (float) (IRI_SIZE-1) - (float) blue_index0;
	float xm = 1.0f - x;
	float ym = 1.0f - y;
	float zm = 1.0f - z;

	float *V000 = &data[red_index0 * 3 + green_index0 * 3 * IRI_SIZE + blue_index0 * 3 * IRI_SIZE * IRI_SIZE];
	float *V001 = &data[red_index0 * 3 + green_index0 * 3 * IRI_SIZE + blue_index1 * 3 * IRI_SIZE * IRI_SIZE];
	float *V010 = &data[red_index0 * 3 + green_index1 * 3 * IRI_SIZE + blue_index0 * 3 * IRI_SIZE * IRI_SIZE];
	float *V011 = &data[red_index0 * 3 + green_index1 * 3 * IRI_SIZE + blue_index1 * 3 * IRI_SIZE * IRI_SIZE];
	float *V100 = &data[red_index1 * 3 + green_index0 * 3 * IRI_SIZE + blue_index0 * 3 * IRI_SIZE * IRI_SIZE];
	float *V101 = &data[red_index1 * 3 + green_index0 * 3 * IRI_SIZE + blue_index1 * 3 * IRI_SIZE * IRI_SIZE];
	float *V110 = &data[red_index1 * 3 + green_index1 * 3 * IRI_SIZE + blue_index0 * 3 * IRI_SIZE * IRI_SIZE];
	float *V111 = &data[red_index1 * 3 + green_index1 * 3 * IRI_SIZE + blue_index1 * 3 * IRI_SIZE * IRI_SIZE];
	float Vxyz[3];

	for ( int i = 0; i < 3; i++ )
	{
		Vxyz[i] = 	
			V000[i] * xm * ym * zm +
			V100[i] * x  * ym * zm +
			V010[i] * xm * y  * zm +
			V001[i] * xm * ym * z +
			V101[i] * x  * ym * z +
			V011[i] * xm * y  * z +
			V110[i] * x  * y  * zm +
			V111[i] * x  * y  * z;
	}

	if ( Vxyz[0] > 1 ) Vxyz[0] = 1;
	if ( Vxyz[0] < 0 ) Vxyz[0] = 0;
	if ( Vxyz[1] > 1 ) Vxyz[1] = 1;
	if ( Vxyz[1] < 0 ) Vxyz[1] = 0;
	if ( Vxyz[2] > 1 ) Vxyz[2] = 1;
	if ( Vxyz[2] < 0 ) Vxyz[2] = 0;

	rgb[0] = Vxyz[0];
	rgb[1] = Vxyz[1];
	rgb[2] = Vxyz[2];
}


void CUIIridas::Trilin8( unsigned char &r, unsigned char &g, unsigned char &b )
{
	float *data = gLut3d.mIriData;

	int red_index0   = (int) ( mLut8[r] * (float) (IRI_SIZE-1) );
	int green_index0 = (int) ( mLut8[g] * (float) (IRI_SIZE-1) );
	int blue_index0  = (int) ( mLut8[b] * (float) (IRI_SIZE-1) );
	
	int red_index1   = red_index0 + 1;
	int green_index1 = green_index0 + 1;
	int blue_index1  = blue_index0 + 1;

	if ( red_index1 == IRI_SIZE ) red_index1--;
	if ( green_index1 == IRI_SIZE ) green_index1--;
	if ( blue_index1 == IRI_SIZE ) blue_index1--;

	float x = mLut8[r] * (float) (IRI_SIZE-1) - (float) red_index0;
	float y = mLut8[g] * (float) (IRI_SIZE-1) - (float) green_index0;
	float z = mLut8[b] * (float) (IRI_SIZE-1) - (float) blue_index0;
	float xm = 1.0f - x;
	float ym = 1.0f - y;
	float zm = 1.0f - z;

	float *V000 = &data[red_index0 * 3 + green_index0 * 3 * IRI_SIZE + blue_index0 * 3 * IRI_SIZE * IRI_SIZE];
	float *V001 = &data[red_index0 * 3 + green_index0 * 3 * IRI_SIZE + blue_index1 * 3 * IRI_SIZE * IRI_SIZE];
	float *V010 = &data[red_index0 * 3 + green_index1 * 3 * IRI_SIZE + blue_index0 * 3 * IRI_SIZE * IRI_SIZE];
	float *V011 = &data[red_index0 * 3 + green_index1 * 3 * IRI_SIZE + blue_index1 * 3 * IRI_SIZE * IRI_SIZE];
	float *V100 = &data[red_index1 * 3 + green_index0 * 3 * IRI_SIZE + blue_index0 * 3 * IRI_SIZE * IRI_SIZE];
	float *V101 = &data[red_index1 * 3 + green_index0 * 3 * IRI_SIZE + blue_index1 * 3 * IRI_SIZE * IRI_SIZE];
	float *V110 = &data[red_index1 * 3 + green_index1 * 3 * IRI_SIZE + blue_index0 * 3 * IRI_SIZE * IRI_SIZE];
	float *V111 = &data[red_index1 * 3 + green_index1 * 3 * IRI_SIZE + blue_index1 * 3 * IRI_SIZE * IRI_SIZE];
	float Vxyz[3];

	for ( int i = 0; i < 3; i++ )
	{
		Vxyz[i] = 	
			V000[i] * xm * ym * zm +
			V100[i] * x  * ym * zm +
			V010[i] * xm * y  * zm +
			V001[i] * xm * ym * z +
			V101[i] * x  * ym * z +
			V011[i] * xm * y  * z +
			V110[i] * x  * y  * zm +
			V111[i] * x  * y  * z;
	}

	if ( Vxyz[0] > 1 ) Vxyz[0] = 1;
	if ( Vxyz[0] < 0 ) Vxyz[0] = 0;
	if ( Vxyz[1] > 1 ) Vxyz[1] = 1;
	if ( Vxyz[1] < 0 ) Vxyz[1] = 0;
	if ( Vxyz[2] > 1 ) Vxyz[2] = 1;
	if ( Vxyz[2] < 0 ) Vxyz[2] = 0;

	r = (unsigned char) ( Vxyz[0] * 255.0f );
	g = (unsigned char) ( Vxyz[1] * 255.0f );
	b = (unsigned char) ( Vxyz[2] * 255.0f );
}


bool CUIIridas::Inc( double *value, double max, double inc )
{
	if ( *value >= max )
	{
		return false;
	}
	*value += inc;
	if ( *value > max ) *value = max;
	return true;
}

bool CUIIridas::Dec( double *value, double min, double inc )
{
	if ( *value <= min )
	{
		return false;
	}
	*value -= inc;
	if ( *value < min ) *value = min;
	return true;
}


void CUIIridas::DrawBracket( float cx, float cy, bool isLandscape )
{
	int x = 0;
	int y = 0;
	int w = 0;
	int h = 0;
	if ( isLandscape )
	{
		x = cx - IRI_BRACKET_S/2;
		y = cy - IRI_BRACKET_L/2;
		w = IRI_BRACKET_S;
		h = IRI_BRACKET_L;
	}
	else
	{
		x = cx - IRI_BRACKET_L/2;
		y = cy - IRI_BRACKET_S/2;
		w = IRI_BRACKET_L;
		h = IRI_BRACKET_S;
	}

	if ( gPrefs.GetMode800() )
	{
		x = x * Globals.mMiniGuiMin;
		y = y * Globals.mMiniGuiMin;
		w = w * Globals.mMiniGuiMin;
		h = h * Globals.mMiniGuiMin;
	}


	GIGE_SETCOLOR3( 1, 1, 1 );

	// draw top
	CUIVisibleButton::RenderRect(x,y,w,2);

	// draw bottom
	CUIVisibleButton::RenderRect(x,y+h-2,w,2);

	// draw left
	CUIVisibleButton::RenderRect(x,y,2,h);

	// draw right
	CUIVisibleButton::RenderRect(x+w-2,y,2,h);

}

void CUIIridas::DrawCWheelBox( float cx, float cy )
{
	int x = (cx + 0.5f) - IRI_CWHEEL_BOX_W/2;
	int y = (cy + 0.5f) - IRI_CWHEEL_BOX_H/2;
	int w = IRI_CWHEEL_BOX_W;
	int h = IRI_CWHEEL_BOX_H;

	if ( gPrefs.GetMode800() )
	{
		x *= Globals.mMiniGuiMin;
		y *= Globals.mMiniGuiMin;
		w *= Globals.mMiniGuiMin;
		h *= Globals.mMiniGuiMin;
	}


	GIGE_SETCOLOR3( 1, 1, 1 );

	// draw top
	CUIVisibleButton::RenderRect(x,y,w,2);

	// draw bottom
	CUIVisibleButton::RenderRect(x,y+h-2,w,2);

	// draw left
	CUIVisibleButton::RenderRect(x,y,2,h);

	// draw right
	CUIVisibleButton::RenderRect(x+w-2,y,2,h);

}

void CUIIridas::CWheelClick( EUIIridas button, int x, int y )
{
	float v[2];
	float n[2];
	float *pos = NULL;
	
	y -= IRI_GADGET_Y  * Globals.mMiniGuiMin;

	switch ( button )
	{
	case UIIRIDAS_OFFSET_CWHEEL:
		pos = mOffsetPos;
		x -= IRI_GADGET_X1 * Globals.mMiniGuiMin;
		break;
	case UIIRIDAS_GAMMA_CWHEEL:
		pos = mGammaPos;
		x -= IRI_GADGET_X2 * Globals.mMiniGuiMin;
		break;
	case UIIRIDAS_COLORGAIN_CWHEEL:
		pos = mColorGainPos;
		x -= IRI_GADGET_X3 * Globals.mMiniGuiMin;
		break;
	}

	v[0] = (float) ( x - pos[0] ) / CWHEEL_SCALAR;
	v[1] = (float) ( y - pos[1] ) / CWHEEL_SCALAR;

	n[0] = pos[0] + v[0];
	n[1] = pos[1] + v[1];

	if ( n[0] * n[0] + n[1] * n[1] < ( float ) IRI_CWHEEL_RADIUS*IRI_CWHEEL_RADIUS )
	{
		// point is within circle
		pos[0] = n[0];
		pos[1] = n[1];
		return;
	}

	float d = sqrt( n[0] * n[0] + n[1] * n[1] );
	float s = (float) IRI_CWHEEL_RADIUS / d;
	pos[0] = n[0] * s;
	pos[1] = n[1] * s;
}


void CUIIridas::CWheelTrack( EUIIridas button, int dx, int dy )
{
	float v[2];
	float n[2];
	float *pos = NULL;

	switch ( button )
	{
	case UIIRIDAS_OFFSET_CWHEEL:
		pos = mOffsetPos;
		break;
	case UIIRIDAS_GAMMA_CWHEEL:
		pos = mGammaPos;
		break;
	case UIIRIDAS_COLORGAIN_CWHEEL:
		pos = mColorGainPos;
		break;
	}

	v[0] = (float) dx / CWHEEL_PIXELS;
	v[1] = (float) dy / CWHEEL_PIXELS;

	n[0] = pos[0] + v[0];
	n[1] = pos[1] + v[1];

	if ( n[0] * n[0] + n[1] * n[1] < ( float ) IRI_CWHEEL_RADIUS*IRI_CWHEEL_RADIUS )
	{
		// point is within circle
		pos[0] = n[0];
		pos[1] = n[1];
		//*maxed = false;
		return;
	}

	//if ( *maxed ) return false;

	float d = sqrt( n[0] * n[0] + n[1] * n[1] );
	float s = (float) IRI_CWHEEL_RADIUS / d;
	pos[0] = n[0] * s;
	pos[1] = n[1] * s;
	//*maxed = true;

	//return true;
}


void CUIIridas::ComputeXYZ( float *pos, float luma, double *xyz )
{
	float sat = 0;
	float degrees = 0;
	float radius = sqrt( pos[0] * pos[0] + pos[1] * pos[1] );
	if ( radius > 0.001 )
	{
		sat = radius / (float) IRI_CWHEEL_RADIUS;
		degrees = asin(-pos[1]/radius ) * 180.0f / PI;
	}
	if ( pos[0] < 0 )
	{
		degrees = 180 - degrees; 
	}
	degrees -= 90.0f;
	while ( degrees < 0 )
		degrees += 360.0f;
	while ( degrees > 360.0f )
		degrees -= 360.0f;

	float r = 0;
	float g = 0;
	float b = 0;
	if ( degrees < 60.0f )
	{
		// red to yellow
		r = 1;
		g = degrees / 60.0f;
	}
	else if ( degrees < 120.0f )
	{
		// yellow to green
		r = 1 - (degrees-60.0f)/60.0f;
		g = 1;
	}
	else if ( degrees < 180.0f )
	{
		// green to cyan
		g = 1;
		b = ( degrees - 120.0f )/ 60.0f;
	}
	else if ( degrees < 240.0f )
	{
		// cyan to blue
		g = 1 - (degrees-180.0f)/60.0f;
		b = 1;
	}
	else if ( degrees < 300.0f )
	{
		// blue to magenta
		b = 1;
		r = ( degrees - 240.0f ) / 60.0f;
	}
	else if ( degrees <= 360.0f )
	{
		// magenta to red
		b = 1 - (degrees-300.0f)/60.0f;
		r = 1;
	}
	else
		assert(0);


	if ( luma < 0 )
	{
		r *= (1 + luma);
		g *= (1 + luma);
		b *= (1 + luma);
	}
	else
	{
		r = 1 - ( ( 1 - r ) * (1-luma));
		g = 1 - ( ( 1 - g ) * (1-luma));
		b = 1 - ( ( 1 - b ) * (1-luma));
	}

	float c = ( luma + 1.0f ) / 2.0f;

	float mx = r * sat + c * ( 1.0f - sat );
	float my = g * sat + c * ( 1.0f - sat );
	float mz = b * sat + c * ( 1.0f - sat );

	xyz[0] = mx * 2 - 1;
	xyz[1] = my * 2 - 1;
	xyz[2] = mz * 2 - 1;
}

void CUIIridas::UpdateOffset( void )
{
	ComputeXYZ( mOffsetPos, (float) mOffsetLuma, mOffsetXYZ[mIridasMode] );
	gIrex->SetLookVectorValue( 
		offsetStr[mIridasMode], 
		mOffsetXYZ[mIridasMode][0], 
		mOffsetXYZ[mIridasMode][1], 
		mOffsetXYZ[mIridasMode][2] 
	);
}

void CUIIridas::UpdateGamma( void )
{
	double xyz[3];
	ComputeXYZ( mGammaPos, (float) mGammaLuma, xyz );
	mGammaXYZ[mIridasMode][0] = -xyz[0];
	mGammaXYZ[mIridasMode][1] = -xyz[1];
	mGammaXYZ[mIridasMode][2] = -xyz[2];

	gIrex->SetLookVectorValue( 
		gammaStr[mIridasMode], 
		mGammaXYZ[mIridasMode][0], 
		mGammaXYZ[mIridasMode][1], 
		mGammaXYZ[mIridasMode][2] 
	);
}

void CUIIridas::UpdateColorGain( void )
{
	ComputeXYZ( mColorGainPos, (float) mColorGainLuma, mColorGainXYZ[mIridasMode] );
	gIrex->SetLookVectorValue( 
		colorGainStr[mIridasMode], 
		mColorGainXYZ[mIridasMode][0], 
		mColorGainXYZ[mIridasMode][1], 
		mColorGainXYZ[mIridasMode][2] 
	);
}

void CUIIridas::Update(void)
{
	gIrex->ReadLook3DLUT(IRI_SIZE, IREX_LUT_ORDER_BGR, gLut3d.mIriData, "");
	gD3D->SetIriTextures();
	Globals.SetUpdateIridasGraphs( true );
}

void CUIIridas::LookFileCancel( void )
{
	delete mLookFileDialog;
	mLookFileDialog = NULL;
	InvalidateRect( Globals.hwnd, NULL, false );
}

void CUIIridas::SaveLookFileOk( void )
{
	char filename[256];
	strcpy( filename, mLookFileDialog->mName );
	CheckFileExtension( filename, FILE_TYPE_LOOK );

	strcpy( mLoadLook, filename ); // For display in the player look color correction

	char lookpath[256];
	strcpy( lookpath, Globals.GetSIDir() );
	strcat( lookpath, filename);
	IRBOOL res = gIrex->bSaveLook( lookpath, 64, 8 );

	// Store saved look name for player look replacement
	strcpy( mSaveLook, lookpath );
	gUIManager->OnReplacePlayerLookFile();

	// Replace current look file in preset only if we are in preview
	if ( isProgramPreviewing() )
	{
		gPrefs.SetLookName( mIndex, lookpath );
		gLut3d.LoadLook( mIndex, filename );
		if ( gLookDialog )
		{
			gLookDialog->UpdateLookNames();
		}
		gD3D->SetLut3DTextures();
	}

	Globals.SetPolledEvent( POLLED_EVENT_DELETEIRIDAS );

	LookFileCancel();
}

void CUIIridas::ReplacePlayerLookFile()
{
	// If there is nothing to replace, or 'replace look' is not checked, exit
	if ( ( strcmp ( mSaveLook, "" ) == 0 ) || ( ! mLookFileDialog->mReplacePlayerLook->GetState() ) )
	{
		return;
	}

	if ( isProgramPlayingSIV() )
	{
		CClipInfoEditorSIV *mClipEditSIV;

		char * filePath = Globals.GetCurrentPlaybackFile();

		char secondFile[ 512 ];
		std::vector<char*> *SIVPaths = new std::vector<char*>();
		SIVPaths->push_back( filePath );
		strcpy( secondFile, filePath );
		bool res = AddStereoFile( secondFile, SIVPaths );

		// If the second file of a stereo SIV pair cannot be found, resize the vector to 1
		if ( ! res )
		{
			SIVPaths->resize( 1 );
		}

		mClipEditSIV = new CClipInfoEditorSIV( SIVPaths );

		mClipEditSIV->Initialize( SIVPaths );
		mClipEditSIV->Read();
		mClipEditSIV->SetLookfileName( mSaveLook );
		mClipEditSIV->Write();
		mClipEditSIV->Close();

		delete SIVPaths;
		delete mClipEditSIV;
	}
	else
	{
		CClipInfoEditorAVI *mClipEditAVI;
		mClipEditAVI = new CClipInfoEditorAVI( Globals.GetCurrentPlaybackFile() );
		mClipEditAVI->Initialize();
		mClipEditAVI->Read();
		mClipEditAVI->SetLookfileName( mSaveLook );
		mClipEditAVI->Write();
		mClipEditAVI->Close();
		delete mClipEditAVI;
	}
}

void CUIIridas::SavePlayerLookFile()
{
	char lookFile[ MAX_PATH ]= "\0";
	int index = gPrefs.GetPlayerLook();
	strcpy( lookFile, gPrefs.GetLookName( index ) );
	gPrefs.SetLookName( 4, lookFile );

	if ( isProgramPlayingSIV() )
	{
		CClipInfoEditorSIV *mClipEditSIV;

		char * filePath = Globals.GetCurrentPlaybackFile();

		char secondFile[ 512 ];
		std::vector<char*> *SIVPaths = new std::vector<char*>();
		SIVPaths->push_back( filePath );
		strcpy( secondFile, filePath );
		bool res = AddStereoFile( secondFile, SIVPaths );

		// If the second file of a stereo SIV pair cannot be found, resize the vector to 1
		if ( ! res )
		{
			SIVPaths->resize( 1 );
		}

		mClipEditSIV = new CClipInfoEditorSIV( SIVPaths );

		mClipEditSIV->Initialize( SIVPaths );
		mClipEditSIV->Read();
		mClipEditSIV->SetLookfileName( lookFile );
		mClipEditSIV->Write();
		mClipEditSIV->Close();

		delete SIVPaths;
		delete mClipEditSIV;
	}
	else
	{
		CClipInfoEditorAVI *mClipEditAVI;
		mClipEditAVI = new CClipInfoEditorAVI( Globals.GetCurrentPlaybackFile() );
		mClipEditAVI->Initialize();
		mClipEditAVI->Read();
		mClipEditAVI->SetLookfileName( lookFile );
		mClipEditAVI->Write();
		mClipEditAVI->Close();
		delete mClipEditAVI;
	}
}

void CUIIridas::OpenSaveLookFileDlg( void )
{
	mLookFileDialog = new CUILookFileDialog;
	InvalidateRect( Globals.hwnd, NULL, false );
}

void CUIIridas::UpdateSliders( EIridasSlider slider )
{
	gIrex->SetLookScalarValue( 
		sliderStr[slider][mIridasMode], 
		mSliderValues[slider][mIridasMode]
	);
}

bool CUIIridas::HandleRightClick( int x, int y )
{
	if ( mTrackballOn )
	{
		mTrackballOn = false;
		mTrackballButton = -1;
		ShowCursor( TRUE );
		return false;
	}

	//buttons
	CUIButton *button = NULL;
	if ( mSet == 0 )
		button = mSet1List;
	else if ( mSet == 1 )
		button = mSet2List;
	else
		button = mSet3List;
	while ( button )
	{
		if ( button->HandleClick(x,y) ) 
			break;
		button = button->GetNext();
	}
	if ( !button ) return false;

	switch ( button->GetID() )
	{
	case UIIRIDAS_OFFSET_BAR:
	case UIIRIDAS_GAMMA_BAR:
	case UIIRIDAS_COLORGAIN_BAR:
	case UIIRIDAS_SAT_BAR:
	case UIIRIDAS_PIVOT_BAR:
	case UIIRIDAS_TEMP_BAR:
	case UIIRIDAS_GAIN_BAR:
	case UIIRIDAS_CONT_BAR:
	case UIIRIDAS_MAG_BAR:
	case UIIRIDAS_OFFSET_CWHEEL:
	case UIIRIDAS_GAMMA_CWHEEL:
	case UIIRIDAS_COLORGAIN_CWHEEL:
	case UIIRIDAS_THRESHOLD_BAR:
		mTrackballButton = button->GetID();
		break;
	default:
		return false;
	}

	mTrackballOn = true;
	ShowCursor( FALSE );
	return true;

	// InvalidateRect( Globals.hwnd, NULL, false );

}

void CUIIridas::UpdateTrackball( int dx, int dy )
{
	switch ( mTrackballButton )
	{
	case UIIRIDAS_OFFSET_BAR:
		if ( Track( mOffsetLuma, -1, 1, -dy ) )
		{
			UpdateOffset();
			Update();
		}
		break;

	case UIIRIDAS_GAMMA_BAR:
		if ( Track( mGammaLuma, -1, 1, -dy ) )
		{
			UpdateGamma();
			Update();
		}
		break;

	case UIIRIDAS_COLORGAIN_BAR:
		if ( Track( mColorGainLuma, -1, 1, -dy ) )
		{
			UpdateColorGain();
			Update();
		}
		break;

	case UIIRIDAS_SAT_BAR:
		if ( Track( mSliderValues[IRIDAS_SLIDER_SAT][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_SAT][0], 
			sliderMinMidMax[IRIDAS_SLIDER_SAT][2], dx ) )
		{
			UpdateSliders(IRIDAS_SLIDER_SAT);
			Update();
		}
		break;

	case UIIRIDAS_PIVOT_BAR:
		if ( Track( mSliderValues[IRIDAS_SLIDER_PIVOT][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_PIVOT][0], 
			sliderMinMidMax[IRIDAS_SLIDER_PIVOT][2], dx ) )
		{
			UpdateSliders(IRIDAS_SLIDER_PIVOT);
			Update();
		}
		break;

	case UIIRIDAS_TEMP_BAR:
		if ( Track( mSliderValues[IRIDAS_SLIDER_TEMP][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_TEMP][0], 
			sliderMinMidMax[IRIDAS_SLIDER_TEMP][2], dx ) )
		{
			UpdateSliders(IRIDAS_SLIDER_TEMP);
			Update();
		}
		break;

	case UIIRIDAS_GAIN_BAR:
		if ( Track( mSliderValues[IRIDAS_SLIDER_OVERALL][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_OVERALL][0], 
			sliderMinMidMax[IRIDAS_SLIDER_OVERALL][2], dx ) )
		{
			UpdateSliders(IRIDAS_SLIDER_OVERALL);
			Update();
		}
		break;

	case UIIRIDAS_CONT_BAR:
		if ( Track( mSliderValues[IRIDAS_SLIDER_CONTRAST][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_CONTRAST][0], 
			sliderMinMidMax[IRIDAS_SLIDER_CONTRAST][2], dx ) )
		{
			UpdateSliders(IRIDAS_SLIDER_CONTRAST);
			Update();
		}
		break;

	case UIIRIDAS_MAG_BAR:
		if ( Track( mSliderValues[IRIDAS_SLIDER_MAGENTA][mIridasMode], 
			sliderMinMidMax[IRIDAS_SLIDER_MAGENTA][0], 
			sliderMinMidMax[IRIDAS_SLIDER_MAGENTA][2], dx ) )
		{
			UpdateSliders(IRIDAS_SLIDER_MAGENTA);
			Update();
		}
		break;

	case UIIRIDAS_OFFSET_CWHEEL:
		CWheelTrack( UIIRIDAS_OFFSET_CWHEEL, dx, dy );
		UpdateOffset();
		Update();
		break;
	case UIIRIDAS_GAMMA_CWHEEL:
		CWheelTrack( UIIRIDAS_GAMMA_CWHEEL, dx, dy );
		UpdateGamma();
		Update();
		break;
	case UIIRIDAS_COLORGAIN_CWHEEL:
		CWheelTrack( UIIRIDAS_COLORGAIN_CWHEEL, dx, dy );
		UpdateColorGain();
		Update();
		break;

	case UIIRIDAS_THRESHOLD_BAR:
		if ( Track( mKeyerInfo.mScale, IRI_THRESHOLD_MIN, IRI_THRESHOLD_MAX, dx ) )
		{
			gIrex->SetLookScalarValue( mKeyerInfo.mScaleName, mKeyerInfo.mScale );
			if ( mKeyerInfo.mScale <= IRI_THRESHOLD_MIN ) 
			{
				mKeyerInfo.mScale = IRI_THRESHOLD_MIN;
			}
			Globals.mIridasVector[1] = (float) ( 1.0 / mKeyerInfo.mScale );
		}
		break;
	}
}

bool CUIIridas::Track( double &value, double min, double max, int dx )
{
	if ( dx < 0 && value == min ) 
		return false;
	if ( dx > 0 && value == max ) 
		return false;

	double range = max - min;
	double d = (double) dx * range / TRACK_PIXELS;

	value += d;
	if ( value < min )
		value = min;
	if ( value > max )
		value = max;
	return true;
}

int CUIIridas::GetActiveLook()
{
	return mActiveLook;
}

LRESULT CUIIridas::OnMouseWheel( UINT uKeys, short zDelta )
{
	DWORD kurt = zDelta;
	return TRUE;
}