/**********************************************************
 *   geo_glui.cpp                                         *
 *     This implements the graphical user interface to    *
 *     facade.  Not everything is implemented yet, but it *
 *     is well under way.                                 *
 *     All "primary" features should be implemented at    *
 *     this point - basic keyframing controls, animation  *
 *     playback, and all parameter modification and file  *
 *     I/O is done.  The interpolated/set controls from   *
 *     the keyboard interface are not supported, as I     *
 *     don't quite understand what they're supposed to do.*
 *                                                        *
 *     Last modified by Alain Deschenes and Andrew Park,  *
 *     February 6, 2003.                                  *
 *     GLUI sucks, but at least the interface is clean.   *
 *                                                        *
 *     Known bugs: none.                                  *
 *     Known issues: Frames higher than 1,000,000 can not *
 *                   be entered.                          *
 *     History:											  *
 *        03.2.08 - Andrew Park - added right-click menu  *
 *                  & rotation to panel					  *             
 *        03.2.06 - Alain Deschenes - Complete UI redesign*
 *        01.3.09 - Gary King - added screenshot utility  *
 *        01.3.09 - Gary King - added anim curve toggle,  *
 *                  play from/to spinner                  *
 *        01.3.07 - Gary King - changed Play control to   *
 *                  reset timer when the button is pressed*
 *        01.3.04 - Gary King - original version          *
 **********************************************************/


#include <stdlib.h> //aadesche VC7
#include <GL/glut.h>	    /* OpenGl headers	- aadesche	     */
#include "GL/glui.h"	    /* OpenGl ui headers				     */
#include <stdio.h>
#include <math.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include "ppm.h" // GCK 3.09.01

// aadesche - for reading from directory
#include <io.h>
#include <string>
#include <vector>
#include <iostream>

#define M_PI 3.14159265358979323846  // GCK 3.11.01

// for vector and string - aadesche
using namespace std;

//  Waaaay too many globals and externs to be considered a clean program, but it works
static int mainWnd;
// aadesche - only one window
static GLUI* controlWnd;



// Erika

static GLUI_EditText* caname;
static GLUI_EditText* cfrEdit;
static GLUI_Spinner* cscale1Spin;
static GLUI_Spinner* cscale2Spin;
static GLUI_Spinner* cscaleFSpin;



// Erika
static GLUI_Checkbox* CamEnableCheck;
static int _cscaleFrom = 0;
static int _cscaleTo = 0;
static float _cscaleFac = 1.0f;

static GLUI_Spinner* parameters[80];
static GLUI_Spinner* frameSpinner;
static GLUI_Spinner* scale1Spin;
static GLUI_Spinner* scale2Spin;
static GLUI_Spinner* scaleFSpin;
static GLUI_Spinner* playFromSpin;
static GLUI_Spinner* playToSpin;

static GLUI_Button* nextButton;
static GLUI_Button* prevButton;
static GLUI_Button* playButton;
static GLUI_Button* delButton;
static GLUI_Button* scaleButton;
static GLUI_Button* batchButton; //  GCK 3.10.01

static GLUI_EditText* fname;
static GLUI_EditText* aname;
static GLUI_EditText* frEdit;

// aadesche - structures and listboxes for directory entries
static GLUI_Listbox* paramDirLB;
static vector<string> paramDir;
static GLUI_Listbox* animKeyDirLB;
static vector<string> animKeyDir;
static GLUI_Listbox* cameraKeyDirLB;
static vector<string> cameraKeyDir;



static int _scaleFrom = 0;
static int _scaleTo = 0;
static int mode = 2;
static int mouth = 1;
static int eye = 1;
static int face = 1;
static int _lrChoice = 0;
static int _dmChoice = 0; // draw mode choice. Added by Andrew 2-3-2003
static int _spChoice = 0.0; // spin choice. Added by Adnrew 2-3-2003

static float _param;
static float _scaleFac = 1.0f;

//  Normally, I don't think this would be necessary to get C and C++ working nicely together.
//  Unfortunately, in this case, it is.

#ifdef __cplusplus
extern "C" {
#endif

struct HighPerformanceTimer;

extern double g_fovy; // GCK 3/11/01
extern double pixdx;  // GCK 3/11/01
extern double pixdy;  // GCK 3/11/01
extern float cpml[], cpmr[];
extern int g_curframe;
extern int g_keys[];
extern int g_nkeys;
extern int g_anim;
extern int g_interpMode;
extern int g_playFrom;
extern int g_playTo;
extern int g_lipsync;
extern char* g_sndFileName;


extern HighPerformanceTimer* animTimer;
extern float anim_frame;

extern int NextLowerKey(int);
extern int NextHigherKey(int);
extern void UpdateObject();
extern void draw_mode_select(int);
extern void WriteLibrary(const char*);
extern void ReadLibrary(const char*, int);
extern int GetRegionPm(char[]);
extern int SetUpKeys();
extern int ReadKey(int); 
extern int WriteKey(int);
extern void PrintKeys(int);
extern int DeleteKey(int);
extern int ScaleKeys(int, int, int);
extern void ReStartTimer(HighPerformanceTimer*);
extern void display(void);
extern void addAction(int, int);
extern void undoAction(void);
extern int LookKey(int);

// Erika
extern int WriteCameraKey(int);
extern int ReadCameraKey(int);
extern int DeleteCameraKey(int);
extern int SaveCameraKeys(char fname[]);
extern int LoadCameraKeys(char fname[]);
extern void ResetCamera();
extern int ScaleCameraKeys(int, int, int);
static void updateCameraState(int);
extern int g_camera;
extern int g_nCamKeys;

// Added by Andrew 2-8-2003
void updateParam();
extern void InitParams();
extern void print_help(void);
extern float RotMatrix[4][4];	/* set by glui rotation widget */
extern void InitMatrix();


/*
	Resets a listbox - aadesche
	Takes a listbox along with a vector of strings corresponding to the
	information it contains and deletes the elements one by one.
*/
void clearListBox(GLUI_Listbox * GLBox, vector<string> myVS) {
	int size = myVS.size();
	for(int i = 0; i < size; i++)
		GLBox->delete_item(i);
}

/*
	Fills a listbox - aadesche
	Takes a listbox along with a vector of strings and adds these strings
	in order, one by one.
*/
void fillListBox(GLUI_Listbox * myBox, vector<string> myVS) {
  vector<string>::iterator theIterator;
  int i = 0;

  //adds the strings one by one using STL iterators
  for( theIterator = myVS.begin(); theIterator != myVS.end(); theIterator++, i++ ) {
    myBox->add_item(i, const_cast<char *>(theIterator->c_str())); 
  }
	
}

/*
	Reads a directory entry and returns a vector of the filenames - aadesche
	The filenames are stored into a vector of strings and the 
	structure is returned.
	NOTE: MSWindows specific code here
*/
vector<string> getDirectory(char * path) {
  vector<string> vectorDirectory;
  char szFileSpec[MAX_PATH];
  sprintf(szFileSpec, "%s\\*.*", path);

  _finddata_t fd;
  long nHandle = _findfirst(szFileSpec, &fd);
  if(nHandle != -1)
    {
      while(_findnext(nHandle, &fd) != -1)
	if (strncmp(fd.name, "..", 2) != 0) // don't add ".."
	  vectorDirectory.push_back(fd.name);
      _findclose(nHandle);
    }
  return vectorDirectory;
}


/*********************************************************************
 *  RGBInvY()                                                        *
 *    Inverts an array of RGB triples in place                       *
 *    Added by GCK 3.09.01                                           *
 *    Slightly modified on 3.10.01 (RGBA, rather than RGB)           *
 *********************************************************************/

static void RGBInvY(unsigned char* buff)
{
	GLint viewport[4];   // GCK 3.09.01 (2)
	int g_width, g_height; // GCK 3.09.01 (2)

	glGetIntegerv(GL_VIEWPORT, viewport); // GCK 3.09.01 (2)
	g_width = viewport[2];   //  GCK 3.09.01 (2)
	g_height = viewport[3];  // GCK 3.09.01 (2)

	int y = g_height-1;
	int i,j;

	for (j=g_height-1; j>=g_height/2; j--)
		for (i = 0; i<g_width; i++)
		{
			int ofs1 = 4*(j*g_width + i);
			int ofs2 = 4*((g_height-1-j)*g_width + i);
			char r1 = buff[ofs2];
			char g1 = buff[ofs2+1];
			char b1 = buff[ofs2+2];
			char a1 = buff[ofs2+3];
			buff[ofs2] = buff[ofs1];
			buff[ofs2+1] = buff[ofs1+1];
			buff[ofs2+2] = buff[ofs1+2];
			buff[ofs2+3] = buff[ofs1+3];
			buff[ofs1] = r1;
			buff[ofs1+1] = g1;
			buff[ofs1+2] = b1;
			buff[ofs1+3] = a1;
		}
}



/*********************************************************************
 *  jitter()                                                         *
 *    Performs jittering, so that the screenshots are antialiased    *
 *    Added by GCK 3.09.01                                           *
 *    Based on Example 10-2 in the OpenGL Programming Guide          *
 *    Easily modifiable for depth of field.                          *
 *********************************************************************/
void jitter(GLdouble pixdx, GLdouble pixdy)  // removed static GCK 3/11
{
	/*  GCK 3.09.01 (2) ----------------> */
	GLint viewport[4];
	int g_width, g_height;

	glGetIntegerv(GL_VIEWPORT, viewport);
	g_width = viewport[2];
	g_height = viewport[3];
	/*  -------------> GCK 3.09.01 (2) */

	GLdouble fov2 = (g_fovy*M_PI) / 360.0; // GCK 3/11/01
	GLdouble top = tan(fov2);  // GCK 3/11/01
	GLdouble bottom = -top;
	GLdouble right = top * ((GLdouble)g_width / (GLdouble)g_height);
	GLdouble left = -right;

	GLdouble xwsize = right - left;
	GLdouble ywsize = top - bottom;
	GLdouble dx, dy;

	dx = -((pixdx*xwsize)/(GLdouble) viewport[2]);
	dy = -((pixdy*ywsize)/(GLdouble) viewport[3]);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glFrustum(left+dx, right+dx, bottom + dy, top+dy, 1.0, 100.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

/*********************************************************************
 *  AAscreenshot()                                                   *
 *    routine to take an anti-aliased screenshot of the current      *
 *    frame.                                                         *
 *    Added by GCK 3.09.01 (2)                                       *
 *    Bug fixed by GCK 3.10.01                                       *
 *********************************************************************/

static void AAscreenshot(char* fileName)
{
	GLint viewport[4];
	int g_width, g_height;

	glGetIntegerv(GL_VIEWPORT, viewport);
	g_width = viewport[2];
	g_height = viewport[3];

	unsigned char* frameBuff = (unsigned char*) malloc(g_width*g_height*4);
	unsigned long* accumBuff = (unsigned long*) malloc(g_width*g_height*4*sizeof(unsigned long));
	int i;

	memset(accumBuff, 0, g_width*g_height*4*sizeof(unsigned long));
	glutSetWindow(mainWnd);

	memset(frameBuff, 0, g_width*g_height*4);
	pixdx = pixdy = -0.33;
	display();
	glReadPixels(0,0,g_width, g_height, GL_RGBA, GL_UNSIGNED_BYTE, frameBuff);
	for (i = 0; i<(g_width*g_height*4); i++) accumBuff[i]+=frameBuff[i];

	memset(frameBuff, 0, g_width*g_height*4);
	pixdx = 0.33;
	pixdy = -pixdx;
	display();
	glReadPixels(0,0,g_width, g_height, GL_RGBA, GL_UNSIGNED_BYTE, frameBuff);
	for (i = 0; i<(g_width*g_height*4); i++) accumBuff[i]+=frameBuff[i];

	memset(frameBuff, 0, g_width*g_height*4);
	pixdx = -0.33;
	pixdy = -pixdx;
	display();
	glReadPixels(0,0,g_width, g_height, GL_RGBA, GL_UNSIGNED_BYTE, frameBuff);
	for (i = 0; i<(g_width*g_height*4); i++) accumBuff[i]+=frameBuff[i];

	memset(frameBuff, 0, g_width*g_height*4);
	pixdx = 0.33;
	pixdy = 0.33;
	display();
	glReadPixels(0,0,g_width, g_height, GL_RGBA, GL_UNSIGNED_BYTE, frameBuff);
	for (i = 0; i<(g_width*g_height*4); i++) accumBuff[i]+=frameBuff[i];

	memset(frameBuff, 0, g_width*g_height*4);
	pixdx = pixdy = 0.0;
	display();
	glReadPixels(0,0,g_width, g_height, GL_RGBA, GL_UNSIGNED_BYTE, frameBuff);
	for (i = 0; i<(g_width*g_height*4); i++) accumBuff[i]+=frameBuff[i];

	memset(frameBuff, 0, g_width*g_height*4);
	for (i = 0; i<(g_width*g_height*4); i++) frameBuff[i] = (unsigned char)(accumBuff[i]/5);
	RGBInvY(frameBuff);

	WritePPM6(fileName,g_width,g_height,frameBuff);

	free(frameBuff);
	free(accumBuff);

	glutPostRedisplay();
}



/*********************************************************************
 *  parameterCB()                                                    *
 *    Called whenever a user changes any spinner control.  Updates   *
 *    the object, and renders the result.                            *
 *********************************************************************/

void parameterCB(int control)
{
	switch (_lrChoice)
	{
	case 0: cpml[control] = cpmr[control] = _param; break;
	case 1: cpml[control] = _param; break;
	case 2: cpmr[control] = _param; break;
	}
	UpdateObject();
	glutPostRedisplay();
}

/***********************************************************************
 *  updatePanelCB()                                                    *
 *    Used to update the parameter values automagically (e.g., when a  *
 *    new library file is loaded, or when the current frame is changed *
 *    Also handles disabling symmetrical controls when the user        *
 *    switches to asymmetrical mode.                                   *
 ***********************************************************************/
void updatePanelCB(int /**/)
{
	int i;

	switch (_lrChoice)
	{
	case 0:
	case 1:
	{ 
		for (i = 1; i<80; i++)
			if (parameters[i]) parameters[i]->set_float_val(cpml[i]);
		break;
	}
	case 2:
	{
		for (i = 1; i<80; i++)
			if (parameters[i]) parameters[i]->set_float_val(cpmr[i]);
		break;
	}
	}
	switch (_lrChoice)
	{
	case 1:
	case 2:
		parameters[12]->disable();
		parameters[15]->disable();
		parameters[72]->disable();
		parameters[73]->disable();
		parameters[10]->disable();
		parameters[11]->disable();
		parameters[19]->disable();
		parameters[20]->disable();
		parameters[54]->disable();
		parameters[55]->disable();
		parameters[56]->disable();
		parameters[33]->disable();
		parameters[53]->disable();
		parameters[35]->disable();
		parameters[36]->disable();
		parameters[58]->disable();
		parameters[59]->disable();
		parameters[57]->disable();
		break;
	case 0:
		parameters[12]->enable();
		parameters[15]->enable();
		parameters[72]->enable();
		parameters[73]->enable();
		parameters[10]->enable();
		parameters[11]->enable();
		parameters[19]->enable();
		parameters[20]->enable();
		parameters[54]->enable();
		parameters[55]->enable();
		parameters[56]->enable();
		parameters[33]->enable();
		parameters[53]->enable();
		parameters[35]->enable();
		parameters[36]->enable();
		parameters[58]->enable();
		parameters[59]->enable();
		parameters[57]->enable();
		break;
	}
}

/***************************************************************
 *  updateModeCB()                                             *
 *    Called whenever a user changes drawing mode              *  
 *    Added by Andrew 2-8-2003								   *
 ***************************************************************/
void updateModeCB( int )
{
	draw_mode_select(_dmChoice);
	UpdateObject();
	glutPostRedisplay();
}


/***************************************************************
 *  idleFunc()                                                 *
 *    Custom idle func to interface with GLUI                  *
 ***************************************************************/
void idleFunc( void )
{
	glutSetWindow(mainWnd);
	glutPostRedisplay();
}

/***************************************************************
 *  frameChangeCB()                                            *
 *     Called when the user changes the frame via the spinner  *
 ***************************************************************/
void frameChangeCB(int /* */)
{
	if (ReadKey(g_curframe))
	{
		UpdateObject();
		updatePanelCB(-1);
		glutPostRedisplay();
	}
}

/****************************************************************
 *  buttonCB                                                    *
 *    Called when a user presses a push button                  *
 ****************************************************************/

void buttonCB(int button)
{
	char buff[255];
	char cmd[255];
	// disable button if field is empty - aadesche
	if (strlen(fname->get_text())==0 && button == 1) return;
	if (strlen(aname->get_text())==0 && button == 4) return;
	if (strlen(caname->get_text())==0 && button == 15) return;
	
	memset(buff, 0, 255);
	memset(cmd,0, 255);
	



	switch(button)
	{
	case 1:
	{   // Save File
		// aadesche
		sprintf(buff,"library\\%s",fname->get_text());
		WriteLibrary(buff);
		clearListBox(paramDirLB, paramDir);
		paramDir = getDirectory(".\\Library");
		fillListBox(paramDirLB, paramDir);
		break;
	}
	case 2:  //  Load File
	{
		// aadesche
		sprintf(buff,".\\Library\\%s", paramDir[paramDirLB->get_int_val()].c_str());

		if (eye) { if (!GetRegionPm("e")) return; ReadLibrary(buff,1); }
		if (mouth) { if (!GetRegionPm("m")) return; ReadLibrary(buff,1); }
		if (face) { ReadLibrary(buff,0); }
		UpdateObject(); 
		updatePanelCB(-1); 
		glutPostRedisplay();

		break;
	}
	case 3: {printf("bye!\n"); exit(0); break;}  // Quit
	case 4:  // Save Sequence
	{
		// aadesche
		sprintf(buff,"Anims\\%s",aname->get_text());

		sprintf(cmd, "copy fas.keys %s",buff);
		system(cmd);
		printf("Writing keys file to %s.\n",buff);

		// aadesche
		clearListBox(animKeyDirLB, animKeyDir);
		animKeyDir = getDirectory(".\\Anims");
		fillListBox(animKeyDirLB, animKeyDir);
		
		break;
	}
	case 5:  // Load Sequence
	{
		// aadesche
		sprintf(buff,".\\Anims\\%s", animKeyDir[animKeyDirLB->get_int_val()].c_str());
		FILE* fd = fopen(buff, "r");
		if (!fd)
		{
			printf("Error reading keys file %s.\n",buff);
			return;
		} else
		{
			printf("Success reading keys file %s.\n",buff);
		}
		fclose(fd);
		sprintf(cmd, "copy %s fas.keys", buff);
		system(cmd);
		g_curframe = SetUpKeys();
		if (ReadKey(g_curframe))
		{
			UpdateObject();
			updatePanelCB(-1);
			glutPostRedisplay();
		}
		if (g_nkeys > 0)
		{ 
			nextButton->enable(); 
			prevButton->enable(); 
			playButton->enable(); 
			delButton->enable(); 
			batchButton->enable();  // GCK 3.10.01
			frameSpinner->enable(); 
			frameSpinner->set_int_limits(0,g_keys[g_nkeys-1]+1, GLUI_LIMIT_WRAP); 
			frameSpinner->set_int_val(g_curframe);

			/*  GCK 3.09.01 -------------> */
			playFromSpin->set_int_limits(0,g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP);
			playToSpin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP);
			playFromSpin->set_int_val(0);
			g_playFrom = 0;
			playToSpin->set_int_val(g_keys[g_nkeys-1]);
			g_playTo = g_keys[g_nkeys-1];
			playFromSpin->enable();
			playToSpin->enable();

			/*  -------> GCK 3.09.01 */
			if (g_nkeys >= 2)
			{
				scale1Spin->enable();
				scale1Spin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP); // GCK 3.09.01 (2)
				scale1Spin->set_int_val(0);
				scale2Spin->enable();
				scale2Spin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP); // GCK 3.09.01 (2)
				scale2Spin->set_int_val(0);
				scaleFSpin->enable();
				scaleButton->enable();
			}
			else
			{
				scale1Spin->disable();
				scale2Spin->disable();
				scaleFSpin->disable();
				scaleButton->disable();
			}
		}
		else 
		{ 
			nextButton->disable(); 
			prevButton->disable(); 
			playButton->disable(); 
			delButton->disable(); 
			scale1Spin->disable();
			scale2Spin->disable();
			scaleFSpin->disable();
			scaleButton->disable();
			frameSpinner->disable();
		}
		break;
	}
	case 6:  // Next Key
	{
		int fr;
		if (g_curframe == g_keys[g_nkeys-1]) fr = g_keys[0];
		else fr = g_keys[NextHigherKey(g_curframe)];
		if (ReadKey(fr))
		{
			frameSpinner->set_int_val(fr);
			g_curframe = fr;
			UpdateObject();
			updatePanelCB(-1);
			glutPostRedisplay();
		}
		break;
	}
	case 7: // Previous Key
	{
		int fr;
		if (g_curframe == g_keys[0]) fr = g_keys[g_nkeys-1];
		else fr = g_keys[NextLowerKey(g_curframe)];
		if (ReadKey(fr))
		{
			frameSpinner->set_int_val(fr);
			g_curframe = fr;
			UpdateObject();
			updatePanelCB(-1);
			glutPostRedisplay();
		}
		break;
	}
	case 8:  // Play Animation
	{
		// changed by GCK 3/07
		if (g_lipsync) sndPlaySound((LPCSTR)g_sndFileName,SND_ASYNC);
		ReStartTimer(animTimer);
		anim_frame=(float)g_playFrom;  // changed by GCK 3.09.01
		g_anim = 1;
		break;
	}
	case 9:  //  Write Key
	{
		int fr = atoi(frEdit->get_text());
		if (LookKey(fr)!=-1) addAction(2,fr);
		else addAction(0,fr);

		if (WriteKey(fr))
		{
			printf("Writing key %d\n",fr);
			g_curframe = fr;
			frameSpinner->set_int_limits(0,g_keys[g_nkeys-1],GLUI_LIMIT_WRAP);
			frameSpinner->set_int_val(fr);
			frameSpinner->enable();
			playButton->enable();
			nextButton->enable();
			prevButton->enable();
			delButton->enable();
			batchButton->enable(); // GCK 3.10.01
			/*  GCK 3.09.01 -------------> */
			playFromSpin->set_int_limits(0,g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP);
			playToSpin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP);
			playFromSpin->set_int_val(0);
			g_playFrom = 0;
			playToSpin->set_int_val(g_keys[g_nkeys-1]);
			g_playTo = g_keys[g_nkeys-1];
			playFromSpin->enable();
			playToSpin->enable();
			/*  -------> GCK 3.09.01 */
			if (g_nkeys >= 2)
			{
				scale1Spin->enable();
				scale1Spin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP); // GCK 3.09.01 (2)
				scale2Spin->enable();
				scale2Spin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP); // GCK 3.09.01 (2)
				scaleFSpin->enable();
				scaleButton->enable();
			}
			UpdateObject();
			glutPostRedisplay();
		}
		else printf("Error writing key %d!\n",fr);
		break;
	}
	case 10: // Delete key
	{
		addAction(1,g_curframe);
		if (g_curframe == g_keys[g_nkeys-1])
		{
			DeleteKey(g_curframe);
			frameSpinner->set_int_limits(0,g_keys[g_nkeys-1], GLUI_LIMIT_WRAP);
			frameSpinner->set_int_val(g_keys[g_nkeys-1]);
			g_curframe = g_keys[g_nkeys-1];
			if (ReadKey(g_curframe))
			{
				UpdateObject();
				updatePanelCB(-1);
				glutPostRedisplay();
			}
			else printf("Internal Error: Program stability may be compromised!\n");
			if (g_nkeys < 2)
			{
				scale1Spin->disable();
				scale2Spin->disable();
				scaleFSpin->disable();
				scaleButton->disable();
				/*  GCK 3.09.01 -----------> */
				playFromSpin->disable();
				playToSpin->disable();
				/*  ----------> GCK 3.09.01 */
			}
			else
			{
				scale1Spin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP); // GCK 3.09.01 (2)
				scale1Spin->set_int_val(0);
				scale2Spin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP); // GCK 3.09.01 (2)
				scale2Spin->set_int_val(0);
				/*  GCK 3.09.01 --------------> */
				playFromSpin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP);
				g_playFrom = 0;
				playFromSpin->set_int_val(0);
				playToSpin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP);
				g_playTo = g_keys[g_nkeys-1];
				playToSpin->set_int_val(g_keys[g_nkeys-1]);
				/*  --------> GCK 3.09.01 */
			}

		}
		else
		{
			DeleteKey(g_curframe);
			if (ReadKey(g_curframe))
			{
				UpdateObject();
				updatePanelCB(-1);
				glutPostRedisplay();
			}
			else printf("Internal Error: Program stability may be compromised!\n");
			if (g_nkeys < 2)
			{
				scale1Spin->disable();
				scale2Spin->disable();
				scaleFSpin->disable();
				playButton->disable();
				scaleButton->disable();
				nextButton->disable();
				prevButton->disable();
				playButton->disable();
				delButton->disable();
				/*  GCK 3.09.01 -----------> */
				playFromSpin->disable();
				playToSpin->disable();
				/*  ----------> GCK 3.09.01 */
			}
		}

		break;
	}
	case 11:  //  scale keys
	{
		int ff = _scaleFrom, lf = _scaleTo, nlf;
		if (_scaleFrom == _scaleTo) return;
		if (_scaleFrom > _scaleTo) { ff = _scaleTo; lf = _scaleFrom; }
		nlf = (int) (_scaleFac * (float)(lf - ff)) + ff; // GCK 3.09.01 (2)
		if (ScaleKeys(nlf, ff, lf)) // GCK 3.09.01 (2)
		{
			frameSpinner->set_int_limits(0,g_keys[g_nkeys-1],GLUI_LIMIT_WRAP);
			frameSpinner->set_int_val(g_curframe);
			/*  GCK 3.09.01 --------------> */
			playFromSpin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP);
			g_playFrom = 0;
			playFromSpin->set_int_val(0);
			playToSpin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP);
			g_playTo = g_keys[g_nkeys-1];
			playToSpin->set_int_val(g_keys[g_nkeys-1]);
			/*  --------> GCK 3.09.01 */
			/*  GCK 3.09.01 (2) -------------> */
			scale1Spin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP); // GCK 3.09.01 (2)
			scale1Spin->set_int_val(0);
			scale2Spin->set_int_limits(0, g_keys[g_nkeys-1], GLUI_LIMIT_CLAMP); // GCK 3.09.01 (2)
			scale2Spin->set_int_val(0);
			/*  -----------> GCK 3.09.01 (2) */
			updatePanelCB(-1);
			UpdateObject();
			glutPostRedisplay();
		}
		break;
	}
	/* GCK 3.09.01 --------------> */
	case 12:   //  Take an anti-aliased screenshot
	{	
		/*  Since not all OpenGL implementations support the accumulation buffer, we will   *
		 *  perform the same effect using glReadPixels().  Unfortunately, most glReadPixels *
		 *  implemtations are dreadfully slow (<25MPixels/sec); however, given the relative *
		 *  infrequency of screen captures, we can afford for this process to be slightly   *
		 *  inefficient.  We use a floating-point accumulation buffer to allow for best     *
		 *  accuracy.   Currently, 5 equally-weighted samples are taken -- this can be      *
		 *  changed relatively easily if desired.                                           */
		char  filename[45];
		char* libname;

		libname = fname->get_text();
		if (libname && strlen(libname)) sprintf(filename,"Shots\\%s_%d.ppm",libname,g_curframe);
		else sprintf(filename,"Shots\\frame_%d.ppm",g_curframe);
		AAscreenshot(filename);
		break;
	}
	/* -----------> GCK 3.09.01  */
	/* GCK 3.09.01 (2) ---------------> */
	case 13:   //  Batch render
	{
		int i;
		char* animname = aname->get_text();
		char filename[45];
		for (i=g_keys[0]; i<=g_keys[g_nkeys-1]; i++)
		{
			ReadKey(i);
			UpdateObject();
			if (animname && strlen(animname)) sprintf(filename,"Movies\\%s_%d.ppm",animname,i);
			else sprintf(filename,"Movies\\anim_%d.ppm",i);
			AAscreenshot(filename);
		}
		ReadKey(g_curframe);
		UpdateObject();
		glutPostRedisplay();
		break;
	}
	/*  --------->  GCK 3.09.01 (2) */
	case 14:  // Undo
	{
		undoAction();
		break;
	}



	/* added by Erika  - modified by aadesche*/

	case 15: {  // Save camera keys to file
		// aadesche
		sprintf(buff,"Camera\\%s",caname->get_text());
		clearListBox(cameraKeyDirLB, cameraKeyDir);
		cameraKeyDir = getDirectory(".\\Camera");
		fillListBox(cameraKeyDirLB, cameraKeyDir);

		printf("%s\n", buff);
		if (buff && strlen(buff)) {
			printf("%s\n", buff);
			SaveCameraKeys(buff);
		}
		break;	
	}

	case 16: {  // Load camera keys from file
		// aadesche
		sprintf(buff,".\\Camera\\%s", cameraKeyDir[cameraKeyDirLB->get_int_val()].c_str());

		if (buff && strlen(buff)) {
			printf("%s\n", buff);
			LoadCameraKeys(buff);

			if (g_nCamKeys > 1) {
				cscale1Spin->enable();
				cscale2Spin->enable();
				cscaleFSpin->enable();
			}
		}
		break;
	}

	case 17: {  // Write Camera Keys
		int fr = atoi(cfrEdit->get_text());
		if (WriteCameraKey(fr)) {
			printf("writing camera key %d\n", fr);
			g_curframe=fr;
			glutPostRedisplay();

			if (g_nCamKeys > 1) {
				cscale1Spin->enable();
				cscale2Spin->enable();
				cscaleFSpin->enable();
			}
		}


		break;
	}
	case 18: {  // Delete Camera Keys
		int fr = atoi(cfrEdit->get_text());
		DeleteCameraKey(fr);
		if (fr == g_curframe) {
			g_curframe = 0;
			ReadKey(0);
			ReadCameraKey(0);
			UpdateObject();
			glutPostRedisplay();
		}

		break;
	}

	case 19: {  // Scale Camera Keys
		int ff = _cscaleFrom, lf = _cscaleTo, nlf;
		nlf = (int) (_cscaleFac * (float)(lf - ff)) + ff;
		ScaleCameraKeys(nlf,ff,lf);
		break;
	}

	case 20: {
		ResetCamera();
		break;
	}

	case 21: {  // Face Reset. Added by Andrew 2-8-2003
		InitParams();
		InitMatrix();
		draw_mode_select(2);
		UpdateObject();
		updateParam();
		glutPostRedisplay();
		break;
	}

	case 22: {  // Print Help. Added by Andrew 2-8-2003
		print_help();
		break;
	}
	
	case 23: {  // Quit. Added by Andrew 2-8-2003
		exit(0);
		break;
	}
	}
}

/**************************************************
 *  updateGUI()                                   *
 *    Only called once playback of an animation   *
 *    completes.  Used to update the panels.      *
 **************************************************/

void updateGUI(void)
{
	PrintKeys(g_curframe);
	frameSpinner->set_int_val(g_curframe);
	UpdateObject();
	updatePanelCB(-1);
	glutPostRedisplay();
}

/**********************************************
 *  updateParam()                             *
 *    Updates parameters with recent values.  *
 *    Added by Andrew 2-8-2003                *
 **********************************************/
void updateParam()
{
	for (int i = 1; i<80; i++)
		if (parameters[i]) parameters[i]->set_float_val(cpml[i]);
}

/********************************************************************
 *  initGLUI()                                                      *
 *      Creates the GLUI windows, initializes all the push buttons, *
 *      spinners, and edit text controls, registers the callback    *
 *      functions, etc.                                             *
 *	originally written by Gary King                                 *
 *  extensively modified by aadesche								*
 *  right-click menu & rotation added to panel by Andrew			*
 ********************************************************************/
void initGLUI(int Wnd)
{
	GLUI_Panel *_lrPanel, *qPanel, *_paramPanel, *_animPanel, *_cameraPanel;
	GLUI_RadioGroup *_dmgroup, *_lrgroup, *_curveGroup;
	GLUI_Checkbox* check;
	GLUI_Rollout *_eyesRollout, *_mouthRollout, *_faceRollout, *_drawmodeRollout, *_rotRollout, *_animRollout, *_cameraRollout, *_helpRollout;
	GLUI_Rotation *_faceRotation;

	mainWnd = Wnd;

	controlWnd = GLUI_Master.create_glui("Controls", 0, 410, 0);

	_paramPanel = controlWnd->add_panel("Parameters",GLUI_PANEL_EMBOSSED);
	_eyesRollout = controlWnd->add_rollout_to_panel(_paramPanel,"Eyes", false);
	_mouthRollout = controlWnd->add_rollout_to_panel(_paramPanel,"Mouth", false);
	_faceRollout = controlWnd->add_rollout_to_panel(_paramPanel,"Face", false);	
	controlWnd->add_separator_to_panel(_paramPanel);
	_drawmodeRollout = controlWnd->add_rollout_to_panel(_paramPanel, "Draw Mode", false);
	_rotRollout = controlWnd->add_rollout_to_panel(_paramPanel, "Rotation", false);

	parameters[1] = controlWnd->add_spinner_to_panel(_eyesRollout, "Lid", GLUI_SPINNER_FLOAT, &_param, 1, parameterCB);
	parameters[1]->set_float_limits(0.0f, 1.0f);
	parameters[1]->set_float_val(0.9f);
	controlWnd->add_separator_to_panel(_eyesRollout);
	parameters[5] = controlWnd->add_spinner_to_panel(_eyesRollout, "Scale X", GLUI_SPINNER_FLOAT, &_param, 5, parameterCB);
	parameters[5]->set_float_limits(0.01f, 3.0f);
	parameters[5]->set_float_val(1.0f);
	parameters[6] = controlWnd->add_spinner_to_panel(_eyesRollout, "Scale Y", GLUI_SPINNER_FLOAT, &_param, 6, parameterCB);
	parameters[6]->set_float_limits(0.01f, 3.0f);
	parameters[6]->set_float_val(1.0f);
	parameters[18] = controlWnd->add_spinner_to_panel(_eyesRollout, "Move X", GLUI_SPINNER_FLOAT, &_param, 18, parameterCB);
	parameters[18]->set_float_limits(-0.1f, 0.1f);
	parameters[18]->set_float_val(0.0f);
	parameters[51] = controlWnd->add_spinner_to_panel(_eyesRollout, "Pupil Rot X", GLUI_SPINNER_FLOAT, &_param, 51, parameterCB);
	parameters[51]->set_float_limits(-60.0f, 60.0f);
	parameters[51]->set_float_val(0.0f);
	parameters[52] = controlWnd->add_spinner_to_panel(_eyesRollout, "Pupil Rot Y", GLUI_SPINNER_FLOAT, &_param, 52, parameterCB);
	parameters[52]->set_float_limits(-60.0f, 60.0f);
	parameters[52]->set_float_val(0.0f);
	controlWnd->add_separator_to_panel(_eyesRollout);
	parameters[7] = controlWnd->add_spinner_to_panel(_eyesRollout, "Brow Center", GLUI_SPINNER_FLOAT, &_param, 7, parameterCB);
	parameters[7]->set_float_limits(0.0f, 1.0f);
	parameters[7]->set_float_val(0.0f);
	parameters[8] = controlWnd->add_spinner_to_panel(_eyesRollout, "Brow Range", GLUI_SPINNER_FLOAT, &_param, 8, parameterCB);
	parameters[8]->set_float_limits(0.0001f, 10.0f);
	parameters[8]->set_float_val(0.0001f);
	parameters[9] = controlWnd->add_spinner_to_panel(_eyesRollout, "Brow Move Y", GLUI_SPINNER_FLOAT, &_param, 9, parameterCB);
	parameters[9]->set_float_limits(-0.2f, 0.2f);
	parameters[9]->set_float_val(0.0f);
	parameters[2] = controlWnd->add_spinner_to_panel(_eyesRollout, "Brow Tip Y", GLUI_SPINNER_FLOAT, &_param, 2, parameterCB);
	parameters[2]->set_float_limits(-0.2f, 0.2f);
	parameters[2]->set_float_val(0.0f);
	parameters[34] = controlWnd->add_spinner_to_panel(_eyesRollout, "Brow Up", GLUI_SPINNER_FLOAT, &_param, 34, parameterCB);
	parameters[34]->set_float_limits(-0.2f, 0.2f);
	parameters[34]->set_float_val(0.0f);
	parameters[4] = controlWnd->add_spinner_to_panel(_mouthRollout, "Jaw Rot", GLUI_SPINNER_FLOAT, &_param, 4, parameterCB);
	parameters[4]->set_float_limits(-0.5f, 25.0f);
	parameters[4]->set_float_val(0.0f);
	parameters[62] = controlWnd->add_spinner_to_panel(_mouthRollout, "Upper Lip", GLUI_SPINNER_FLOAT, &_param, 62, parameterCB);
	parameters[62]->set_float_limits(-0.2f, 0.2f);
	parameters[62]->set_float_val(0.0f);
	parameters[12] = controlWnd->add_spinner_to_panel(_mouthRollout, "Scale X", GLUI_SPINNER_FLOAT, &_param, 12, parameterCB);
	parameters[12]->set_float_limits(0.1f, 3.0f);
	parameters[12]->set_float_val(1.0f);
	parameters[15] = controlWnd->add_spinner_to_panel(_mouthRollout, "Thickness", GLUI_SPINNER_FLOAT, &_param, 15, parameterCB);
	parameters[15]->set_float_limits(0.00f, 0.09f);
	parameters[15]->set_float_val(0.00f);
	parameters[79] = controlWnd->add_spinner_to_panel(_mouthRollout, "Smile", GLUI_SPINNER_FLOAT, &_param, 79, parameterCB);
	parameters[79]->set_float_limits(-0.2f, 0.2f);
	parameters[79]->set_float_val(0.0f);
	parameters[72] = controlWnd->add_spinner_to_panel(_mouthRollout, "Top Lip \"o\"", GLUI_SPINNER_FLOAT, &_param, 72, parameterCB);
	parameters[72]->set_float_limits(-0.2f, 0.2f);
	parameters[72]->set_float_val(0.0f);
	parameters[73] = controlWnd->add_spinner_to_panel(_mouthRollout, "Bot Lip \"o\"", GLUI_SPINNER_FLOAT, &_param, 73, parameterCB);
	parameters[73]->set_float_limits(-0.2f, 0.2f);
	parameters[73]->set_float_val(0.0f);
	controlWnd->add_separator_to_panel(_mouthRollout);
	parameters[63] = controlWnd->add_spinner_to_panel(_mouthRollout, "Lip Corn X", GLUI_SPINNER_FLOAT, &_param, 63, parameterCB);
	parameters[63]->set_float_limits(-0.2f, 0.2f);
	parameters[63]->set_float_val(0.0f);
	parameters[69] = controlWnd->add_spinner_to_panel(_mouthRollout, "Top Lip Out X", GLUI_SPINNER_FLOAT, &_param, 69, parameterCB);
	parameters[69]->set_float_limits(-0.2f, 0.2f);
	parameters[69]->set_float_val(0.0f);
	parameters[66] = controlWnd->add_spinner_to_panel(_mouthRollout, "Top Lip In X", GLUI_SPINNER_FLOAT, &_param, 66, parameterCB);
	parameters[66]->set_float_limits(-0.2f, 0.2f);
	parameters[66]->set_float_val(0.0f);
	controlWnd->add_separator_to_panel(_mouthRollout);
	parameters[16] = controlWnd->add_spinner_to_panel(_mouthRollout, "Top Lip Mid X", GLUI_SPINNER_FLOAT, &_param, 16, parameterCB);
	parameters[16]->set_float_limits(-0.2f, 0.2f);
	parameters[16]->set_float_val(0.0f);
	parameters[64] = controlWnd->add_spinner_to_panel(_mouthRollout, "Lip Corn Y", GLUI_SPINNER_FLOAT, &_param, 64, parameterCB);
	parameters[64]->set_float_limits(-0.2f, 0.2f);
	parameters[64]->set_float_val(0.0f);
	parameters[70] = controlWnd->add_spinner_to_panel(_mouthRollout, "Top Lip Out Y", GLUI_SPINNER_FLOAT, &_param, 70, parameterCB);
	parameters[70]->set_float_limits(-0.2f, 0.2f);
	parameters[70]->set_float_val(0.0f);
	parameters[67] = controlWnd->add_spinner_to_panel(_mouthRollout, "Top Lip In Y", GLUI_SPINNER_FLOAT, &_param, 67, parameterCB);
	parameters[67]->set_float_limits(-0.2f, 0.2f);
	parameters[67]->set_float_val(0.0f);
	parameters[17] = controlWnd->add_spinner_to_panel(_mouthRollout, "Top Lip Mid Y", GLUI_SPINNER_FLOAT, &_param, 17, parameterCB);
	parameters[17]->set_float_limits(-0.2f, 0.2f);
	parameters[17]->set_float_val(0.0f);
	controlWnd->add_separator_to_panel(_mouthRollout);
	parameters[65] = controlWnd->add_spinner_to_panel(_mouthRollout, "Lip Corn Z", GLUI_SPINNER_FLOAT, &_param, 65, parameterCB);
	parameters[65]->set_float_limits(-0.2f, 0.2f);
	parameters[65]->set_float_val(0.0f);
	parameters[71] = controlWnd->add_spinner_to_panel(_mouthRollout, "Top Lip Out Z", GLUI_SPINNER_FLOAT, &_param, 71, parameterCB);
	parameters[71]->set_float_limits(-0.2f, 0.2f);
	parameters[71]->set_float_val(0.0f);
	parameters[68] = controlWnd->add_spinner_to_panel(_mouthRollout, "Top Lip In Z", GLUI_SPINNER_FLOAT, &_param, 68, parameterCB);
	parameters[68]->set_float_limits(-0.2f, 0.2f);
	parameters[68]->set_float_val(0.0f);
	parameters[74] = controlWnd->add_spinner_to_panel(_mouthRollout, "Top Lip Z", GLUI_SPINNER_FLOAT, &_param, 74, parameterCB);
	parameters[74]->set_float_limits(-0.2f, 0.2f);
	parameters[74]->set_float_val(0.0f);
	controlWnd->add_separator_to_panel(_mouthRollout);
	parameters[78] = controlWnd->add_spinner_to_panel(_mouthRollout, "Bot Lip Out Y", GLUI_SPINNER_FLOAT, &_param, 78, parameterCB);
	parameters[78]->set_float_limits(-0.2f, 0.2f);
	parameters[78]->set_float_val(0.0f);
	parameters[77] = controlWnd->add_spinner_to_panel(_mouthRollout, "Bot Lip In Y", GLUI_SPINNER_FLOAT, &_param, 77, parameterCB);
	parameters[77]->set_float_limits(-0.2f, 0.2f);
	parameters[77]->set_float_val(0.0f);
	parameters[76] = controlWnd->add_spinner_to_panel(_mouthRollout, "Bot Lip Mid Y", GLUI_SPINNER_FLOAT, &_param, 76, parameterCB);
	parameters[76]->set_float_limits(-0.2f, 0.2f);
	parameters[76]->set_float_val(0.0f);
	parameters[75] = controlWnd->add_spinner_to_panel(_mouthRollout, "Bot Lip Z", GLUI_SPINNER_FLOAT, &_param, 75, parameterCB);
	parameters[75]->set_float_limits(-0.2f, 0.2f);
	parameters[75]->set_float_val(0.0f);
	controlWnd->add_separator_to_panel(_faceRollout);
	parameters[10] = controlWnd->add_spinner_to_panel(_faceRollout, "Nose Tip ScX", GLUI_SPINNER_FLOAT, &_param, 10, parameterCB);
	parameters[10]->set_float_limits(0.1f, 3.0f);
	parameters[10]->set_float_val(1.0f);
	parameters[11] = controlWnd->add_spinner_to_panel(_faceRollout, "Bridge ScX", GLUI_SPINNER_FLOAT, &_param, 11, parameterCB);
	parameters[11]->set_float_limits(0.1f, 3.0f);
	parameters[11]->set_float_val(1.0f);
	parameters[27] = controlWnd->add_spinner_to_panel(_faceRollout, "Nose Tip Y", GLUI_SPINNER_FLOAT, &_param, 27, parameterCB);
	parameters[27]->set_float_limits(-0.2f, 0.2f);
	parameters[27]->set_float_val(0.0f);
	parameters[26] = controlWnd->add_spinner_to_panel(_faceRollout, "Nose Tip Z", GLUI_SPINNER_FLOAT, &_param, 26, parameterCB);
	parameters[26]->set_float_limits(-0.2f, 0.2f);
	parameters[26]->set_float_val(0.0f);
	parameters[19] = controlWnd->add_spinner_to_panel(_faceRollout, "Jaw ScX", GLUI_SPINNER_FLOAT, &_param, 19, parameterCB);
	parameters[19]->set_float_limits(0.1f, 3.0f);
	parameters[19]->set_float_val(1.0f);
	parameters[20] = controlWnd->add_spinner_to_panel(_faceRollout, "Cheek ScX", GLUI_SPINNER_FLOAT, &_param, 20, parameterCB);
	parameters[20]->set_float_limits(0.1f, 3.0f);
	parameters[20]->set_float_val(1.0f);
	parameters[32] = controlWnd->add_spinner_to_panel(_faceRollout, "Chin Y", GLUI_SPINNER_FLOAT, &_param, 32, parameterCB);
	parameters[32]->set_float_limits(-0.2f, 0.2f);
	parameters[32]->set_float_val(0.0f);
	parameters[31] = controlWnd->add_spinner_to_panel(_faceRollout, "Chin Z", GLUI_SPINNER_FLOAT, &_param, 31, parameterCB);
	parameters[31]->set_float_limits(-0.2f, 0.2f);
	parameters[31]->set_float_val(0.0f);
	controlWnd->add_separator_to_panel(_faceRollout);
	parameters[54] = controlWnd->add_spinner_to_panel(_faceRollout, "Rot Neck X", GLUI_SPINNER_FLOAT, &_param, 54, parameterCB);
	parameters[54]->set_float_limits(-50.0f, 50.0f);
	parameters[54]->set_float_val(0.0f);
	parameters[55] = controlWnd->add_spinner_to_panel(_faceRollout, "Rot Neck Y", GLUI_SPINNER_FLOAT, &_param, 55, parameterCB);
	parameters[55]->set_float_limits(-50.0f, 50.0f);
	parameters[55]->set_float_val(0.0f);
	parameters[56] = controlWnd->add_spinner_to_panel(_faceRollout, "Rot Neck Z", GLUI_SPINNER_FLOAT, &_param, 56, parameterCB);
	parameters[56]->set_float_limits(-50.0f, 50.0f);
	parameters[56]->set_float_val(0.0f);
	parameters[33] = controlWnd->add_spinner_to_panel(_faceRollout, "Neck Sc", GLUI_SPINNER_FLOAT, &_param, 33, parameterCB);
	parameters[33]->set_float_limits(0.1f, 1.5f);
	parameters[33]->set_float_val(1.0f);
	parameters[53] = controlWnd->add_spinner_to_panel(_faceRollout, "Neck Len", GLUI_SPINNER_FLOAT, &_param, 53, parameterCB);
	parameters[53]->set_float_limits(-0.3f, 0.3f);
	parameters[53]->set_float_val(0.0f);
	parameters[35] = controlWnd->add_spinner_to_panel(_faceRollout, "Chin-Mouth", GLUI_SPINNER_FLOAT, &_param, 35, parameterCB);
	parameters[35]->set_float_limits(0.1f, 3.0f);
	parameters[35]->set_float_val(1.0f);
	parameters[36] = controlWnd->add_spinner_to_panel(_faceRollout, "Chin-Eye", GLUI_SPINNER_FLOAT, &_param, 36, parameterCB);
	parameters[36]->set_float_limits(0.1f, 3.0f);
	parameters[36]->set_float_val(1.0f);
	parameters[58] = controlWnd->add_spinner_to_panel(_faceRollout, "Fhead Sc", GLUI_SPINNER_FLOAT, &_param, 58, parameterCB);
	parameters[58]->set_float_limits(0.1f, 3.0f);
	parameters[58]->set_float_val(1.0f);
	parameters[59] = controlWnd->add_spinner_to_panel(_faceRollout, "Fhead Cut", GLUI_SPINNER_FLOAT, &_param, 59, parameterCB);
	parameters[59]->set_float_limits(0.0f, 1.5f);
	parameters[59]->set_float_val(1.0f);
	parameters[57] = controlWnd->add_spinner_to_panel(_faceRollout, "Squash", GLUI_SPINNER_FLOAT, &_param, 57, parameterCB);
	parameters[57]->set_float_limits(0.5f, 2.6f);
	parameters[57]->set_float_val(1.0f);	
	_dmgroup = controlWnd->add_radiogroup_to_panel(_drawmodeRollout, &_dmChoice, -1, updateModeCB);
	controlWnd->add_radiobutton_to_group(_dmgroup, "Wireframe");
	controlWnd->add_radiobutton_to_group(_dmgroup, "Polygonal Patches");
	controlWnd->add_radiobutton_to_group(_dmgroup, "Smooth Surface");
	_faceRotation = controlWnd->add_rotation_to_panel(_rotRollout, "Rotate Face", (float *) RotMatrix, -1, NULL);
	_faceRotation->set_spin(1.0);
	controlWnd->add_button_to_panel(_paramPanel, "Face Reset", 21, buttonCB);
	controlWnd->add_button_to_panel(_paramPanel, "Print Help", 22, buttonCB);
	controlWnd->add_button_to_panel(_paramPanel, "Quit", 23, buttonCB);
	controlWnd->add_column_to_panel(_paramPanel,false);

	_lrgroup = controlWnd->add_radiogroup_to_panel(_paramPanel, &_lrChoice, -1, updatePanelCB);
	controlWnd->add_radiobutton_to_group(_lrgroup, "Both");
	controlWnd->add_radiobutton_to_group(_lrgroup, "Left Only");
	controlWnd->add_radiobutton_to_group(_lrgroup, "Right Only");
	
	qPanel = controlWnd->add_panel_to_panel(_paramPanel, "");
	fname = controlWnd->add_edittext_to_panel(qPanel, "Filename: ", GLUI_EDITTEXT_TEXT);
	controlWnd->add_button_to_panel(qPanel,"Save", 1, buttonCB);

	paramDirLB = controlWnd->add_listbox_to_panel(qPanel, "Open File:");
	paramDir = getDirectory(".\\Library");
    fillListBox(paramDirLB, paramDir);

	controlWnd->add_button_to_panel(qPanel,"Load", 2, buttonCB);

//	controlWnd->add_button_to_panel(qPanel,"Quit", 3, buttonCB);
//	controlWnd->add_button_to_panel(qPanel,"Screenshot", 12, buttonCB);  // GCK 3.09.01
//	controlWnd->add_button_to_panel(qPanel,"Undo",14,buttonCB);

	check = controlWnd->add_checkbox_to_panel(qPanel, "Read Face", &face);
	check->set_int_val(1);
	check = controlWnd->add_checkbox_to_panel(qPanel, "Read Mouth", &mouth);
	check->set_int_val(1);
	check = controlWnd->add_checkbox_to_panel(qPanel, "Read Eyes", &eye);
	check->set_int_val(1);
	
	controlWnd->add_column(true);
//  now initialize the widgets in the animation control window
	_animPanel = controlWnd->add_panel("Animation",GLUI_PANEL_EMBOSSED);
	_animRollout = controlWnd->add_rollout_to_panel(_animPanel,"Animation", false);

	frEdit = controlWnd->add_edittext_to_panel(_animRollout, "New Frame:");
	frEdit->set_int_limits(0,1000000,GLUI_LIMIT_CLAMP);
	controlWnd->add_button_to_panel(_animRollout, "Write Key", 9, buttonCB);
	controlWnd->add_separator_to_panel(_animRollout);

	frameSpinner = controlWnd->add_spinner_to_panel(_animRollout, "Frame",GLUI_SPINNER_INT, &g_curframe, -1, frameChangeCB);
	frameSpinner->set_int_val(0);
	frameSpinner->disable();
	delButton = controlWnd->add_button_to_panel(_animRollout, "Delete Key", 10, buttonCB);
	delButton->disable();
	controlWnd->add_separator_to_panel(_animRollout);

	playButton = controlWnd->add_button_to_panel(_animRollout, "Play Anim", 8, buttonCB);
	playButton->disable();
	nextButton = controlWnd->add_button_to_panel(_animRollout, "Next Key", 6, buttonCB);
	nextButton->disable();
	prevButton = controlWnd->add_button_to_panel(_animRollout, "Prev Key", 7, buttonCB);
	prevButton->disable();
	controlWnd->add_separator_to_panel(_animRollout);

	_curveGroup = controlWnd->add_radiogroup_to_panel(_animRollout, &g_interpMode);
	controlWnd->add_radiobutton_to_group(_curveGroup, "Linear");
	controlWnd->add_radiobutton_to_group(_curveGroup, "Quadratic");
	controlWnd->add_radiobutton_to_group(_curveGroup, "Noisy");

	controlWnd->add_separator_to_panel(_animRollout);
	scaleFSpin = controlWnd->add_spinner_to_panel(_animRollout, "Scale Fac", GLUI_SPINNER_FLOAT, &_scaleFac);
	scaleFSpin->set_float_val(1.0f);
	scaleFSpin->set_float_limits(0.1f, 10.0f);
	scaleFSpin->disable();
	scaleButton = controlWnd->add_button_to_panel(_animRollout, "Scale Anim", 11, buttonCB);
	scaleButton->disable();
    /*  GCK 3.09.01 ---> */
	batchButton = controlWnd->add_button_to_panel(_animRollout, "Batch Render", 13, buttonCB);  // GCK 3.10.01
	batchButton->disable();  // GCK 3.10.01
	/* ---> */
	controlWnd->add_separator_to_panel(_animRollout);

	scale1Spin = controlWnd->add_spinner_to_panel(_animRollout, "Scale From",GLUI_SPINNER_INT, &_scaleFrom);
	scale2Spin = controlWnd->add_spinner_to_panel(_animRollout, "Scale To", GLUI_SPINNER_INT, &_scaleTo);
	scale1Spin->set_int_val(0);
	scale2Spin->set_int_val(0);
	scale1Spin->disable();
	scale2Spin->disable();
	/*  GCK 3.09.01 ----> */
	controlWnd->add_separator_to_panel(_animRollout);
	playFromSpin = controlWnd->add_spinner_to_panel(_animRollout, "Play From",GLUI_SPINNER_INT, &g_playFrom);
	playToSpin   = controlWnd->add_spinner_to_panel(_animRollout, "Play To",  GLUI_SPINNER_INT, &g_playTo);
	playFromSpin->disable();
	playToSpin->disable();
	/*  ---> GCK 3.09.01 */
	controlWnd->add_column_to_panel(_animPanel);
	aname = controlWnd->add_edittext_to_panel(_animPanel, "Key File: ", GLUI_EDITTEXT_TEXT);
	controlWnd->add_button_to_panel(_animPanel, "Save Sequence", 4, buttonCB);

	animKeyDirLB = controlWnd->add_listbox_to_panel(_animPanel, "Open File:");
	animKeyDir = getDirectory(".\\Anims");
    fillListBox(animKeyDirLB, animKeyDir);

	controlWnd->add_button_to_panel(_animPanel, "Load Sequence", 5, buttonCB);
	controlWnd->set_main_gfx_window(mainWnd);
	controlWnd->set_main_gfx_window(mainWnd);
	GLUI_Master.set_glutIdleFunc(idleFunc);	
	
	controlWnd->add_separator();

	_cameraPanel = controlWnd->add_panel("Camera",GLUI_PANEL_EMBOSSED);
	_cameraRollout = controlWnd->add_rollout_to_panel(_cameraPanel,"Camera", false);
	_helpRollout = controlWnd->add_rollout_to_panel(_cameraRollout,"Help", false);


	/* added by Erika */

	controlWnd->add_statictext_to_panel(_helpRollout,"Up Key:Pan up");
	controlWnd->add_statictext_to_panel(_helpRollout,"Down Key:Pan down");
	controlWnd->add_statictext_to_panel(_helpRollout,"Left Key:	Pan Left");
	controlWnd->add_statictext_to_panel(_helpRollout,"Right Key:	Pan Right");
	controlWnd->add_statictext_to_panel(_helpRollout,"Home:		Backward");
	controlWnd->add_statictext_to_panel(_helpRollout,"PgUp:		Forward");
	controlWnd->add_statictext_to_panel(_helpRollout,"End:			Zoom in");
	controlWnd->add_statictext_to_panel(_helpRollout,"PgDn:		Zoom out");


	cfrEdit = controlWnd->add_edittext_to_panel(_cameraRollout,"New Frame:");
	controlWnd->add_button_to_panel(_cameraRollout,"Write Key", 17, buttonCB);
	controlWnd->add_button_to_panel(_cameraRollout,"Delete Key", 18, buttonCB);

	controlWnd->add_separator_to_panel(_cameraRollout);
	cscale1Spin = controlWnd->add_spinner_to_panel(_cameraRollout,"Scale From",GLUI_SPINNER_INT, &_cscaleFrom);
	cscale2Spin = controlWnd->add_spinner_to_panel(_cameraRollout,"Scale To", GLUI_SPINNER_INT, &_cscaleTo);
	cscale1Spin->set_int_val(0);
	cscale2Spin->set_int_val(0);
	cscale1Spin->disable();
	cscale2Spin->disable();
	cscaleFSpin = controlWnd->add_spinner_to_panel(_cameraRollout,"Scale Fac", GLUI_SPINNER_FLOAT, &_cscaleFac);
	cscaleFSpin->set_float_val(1.0f);
	cscaleFSpin->set_float_limits(0.1f, 10.0f);
	cscaleFSpin->disable();
	controlWnd->add_button_to_panel(_cameraRollout,"Scale Keys", 19, buttonCB);

	controlWnd->add_separator_to_panel(_cameraRollout);
	controlWnd->add_button_to_panel(_cameraRollout,"Reset Camera", 20, buttonCB);
	controlWnd->add_separator_to_panel(_cameraRollout);
	CamEnableCheck = controlWnd->add_checkbox_to_panel(_cameraRollout,"Enable Camera", &g_camera, -1, updateCameraState);
	CamEnableCheck->set_int_val(1);

	controlWnd->add_column_to_panel(_cameraPanel);

	caname = controlWnd->add_edittext_to_panel(_cameraPanel,"Key File: ", GLUI_EDITTEXT_TEXT);
	controlWnd->add_button_to_panel(_cameraPanel,"Save to file", 15, buttonCB);

	cameraKeyDirLB = controlWnd->add_listbox_to_panel(_cameraPanel,"Open File:");
	cameraKeyDir = getDirectory(".\\Camera");
    fillListBox(cameraKeyDirLB, cameraKeyDir);

	controlWnd->add_button_to_panel(_cameraPanel,"Load from file", 16, buttonCB);

	
}	

void updateCameraState(int)
{

	printf("g_camera toggled: %d\n", g_camera);

}



#ifdef __cplusplus
}
#endif