/*   This project was originally started by:
 *   Jordan Maynard
 *   email: maynard@rohan.sdsu.edu
 *   in spring 2000.
 *
 *   The project was continued during the same semester by
 *   Jerry Kuzminsky
 *	 email: kuzminsk@rohan.sdsu.edu
 *
 *   Functions added:
 *   EnableLight0, 
 *   EnableLight1,
 *	 EnableLight2,
 *   readButton();,
 *   readSliders();
 *   spinAxis();
 *   
 *   Many existiong functions were modified.  All my coments end with j.k.
 *	 New features:
 *   Automatic Rotation along X, Y, Z axis,
 *   Spiffier X, Y, Z letters with rings rotating around them,
 *   Cone tips on the axis,
 *	 thicker lines in many places replaced with 3D objjects,
 *   lights and shading - 3 sources of light,
 *   MUI interface with the functions
 *
 *	 Parts removed:
 *	 keyboard function and submenu function are no longer needed and were removed.
 *   their functions are now handled by MUI and/or right mouse button menus.
 *	 j.k.
 */

#include "glut.h"         // Header File For The GLUT Library
//#include <GL/glu.h>		     // Header File For The Glu32 Library
#include "mui.h"          // Here comes MUI j.k.
#include <stdio.h>		     // Header File For Standard I/O
#include <math.h>            // Header File For Math... cos() and sin()

// Defines... 
#define SPACE 30.0          
#define LENEDGE 0.3      
#define POINTSPERSIDE 8  // REDUCE THIS TO RUN FASTER
#define STARTCOORD (POINTSPERSIDE)*LENEDGE/2
#define FUNCTIONCOUNT 15
#define M_PI 3.14159265358979323846

// Function definitions as well j.k.
void Display(void);
void drawaxis(void);
void EnableLight0(void);
void EnableLight1(void);
void EnableLight2(void);
void Idle(void);
void init(void);
void initDisplayList(int);
void menu(int m);
void Motion(int, int);
void normalize(float *);
void normCrossProd(float * , float* , float* );
void readButton(muiObject * ,enum muiReturnValue );
void readSliders(muiObject * ,enum muiReturnValue );
void reshape(int w, int h);
void spinAxis(void);

// Global Variables...
long t  = 0 ;		// used for calculating the framerate...
long ot = 0;        
int muiWin, mW;

// state flags, ie is lighting on? is smoothing on? etc...
int  lighting  = 1;   
int  smoothing = 1;
int  wire      = 1;
int  axes      = 1;
int  max       = 5;
int  min       = 4;
int  tex       = 1;
int  axe       = 0;
int  Xx        = 0;
int  Yy        = 0;
int  Zz        = 0; 
long oldx      = 0;
long oldy      = 0;
int  incr      = 0; 
int  color     = 0;
int  env       = 1;
int  spin      = 1;
int  mode      = 3;
long anim      = 1;
long frames    = 0;
int  fps       = 0;

GLfloat pcx = 0;
GLfloat pcy = 0;
GLfloat rr  = 0.5;
GLfloat px  = 0;
GLfloat py  = 0;

// set up lighting and shading models
GLfloat matSpecular[]    =  { (GLfloat)0.9, (GLfloat)0.9, (GLfloat)0.9, (GLfloat)1.0   };
GLfloat matShininess[]   =  { (GLfloat)60.0 };
GLfloat white_light[]    =  { 1.0, 1.0, 1.0, 0.0  };
GLfloat spot_direction[] =  { 0.0, 0.0, 0.0       };
GLfloat lightPosition[]  =  { -1.0,-20.0,-1.0, 1.0  };
GLfloat light_position1[]=  {  1.0, -20.0,  1.0, 1.0 }; 
GLfloat light_position2[]=  { 10.0,  20.0,-10.0, 1.0 }; 

GLUquadricObj *ZZ;

// string for the title of the window with the fps...
char s[100], rs[32] = { "POINT CHARGE" };

// texture index...
GLuint	texture[1], startList;	

// Defines a point in 3-Space...
struct Point3d
{
    GLfloat x, y, z;
};

struct Point3d Coil[200] ; 

// An array of 3-Space points to represent the functions...
struct Point3d p[POINTSPERSIDE][POINTSPERSIDE][POINTSPERSIDE];

// To transform the view angle...
GLfloat spinX = 0.0, spinY = -0.5, spinZ = 0.0, SpiN = 0;

// To spin the function...  make x and y non-zero to rotate on those axes...
GLfloat  x = 0.00, y = 0.00, z = 0.70;

// Which display list to use (function)
int dispList = 2;
int PointChargeList = 1;

// Every mui object and one label for the slider  j.k.
muiObject *FS, *WM, *PC, *ARC, *COIL, *T3D, *AN, *RX, *RY, *RZ, *SR, *XX, *SL, *SLlabel ;

// Standard normalization ... 
void normalize(float v[3])
{
    float d = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
    d = 1/d;
	if (d != 0.0) /* avoid division by zero */
  {
	v[0] /= d;
	v[1] /= d;
	v[2] /= d;
    }
}

// Spin around axis j.k.
void spinAxis(void)
{
GLfloat step =0.5;

  glPushMatrix();
	if(Xx == 1 )
		spinX += step;     
	if(Yy == 1)
		spinY += step;
	if(Zz == 1)
		spinZ += step;
  glPopMatrix();
 glutPostRedisplay();
}

// Glut idle callback... spins!

void Idle(void)
{
  int i = 0;
	  SpiN  += 0.5;
  if(0)
    {
      spinZ +=   z;     
      spinX +=   x;    
      spinY +=   y;
	}
  anim+=incr;

// Spin axis will only actually "spin" if called and x, y or z is set. j.k.

 spinAxis();



  if (spinZ >= 360.0)

    spinZ -= 360.0;

  

  if (spinX >= 360.0)

    

    spinX -= 360.0;

  

  if (spinY >= 360.0)

    

    spinY -= 360.0;



  if (SpiN >= 360.0 )

	SpiN -=  360.0;		

  

  for( i = 0; i<200; i++)

    {

      if(mode == 2)

	{

	  Coil[i].x = sin(i*M_PI/10)*.7;

	  Coil[i].y = cos(i*M_PI/10)*.7;

	  Coil[i].z = (i*-0.009)+.7;

	}

      if(mode == 1)

	{

	  Coil[i].x = cos(i*0.016)*.7;

	  Coil[i].y = .0-sin(i*.016)*.7;

	  Coil[i].z = 0;

	}

  }

  // IMPORTANT:  since we have two windows graph and mui controls we must 

  // constantly remind that the graph window is the one to focus attention on

  // or the program will resize mui window and any sort of idle-based functions

  // like spin etc. will not work.		j.k.

  glutSetWindow( mW );

  glutPostRedisplay();

}







// Calc normal cross product

void normCrossProd(float v1[3], float v2[3], float out[3])

{

    out[0] = (v1[1]*v2[2]) - v1[2]*v2[1];

    out[1] = (v1[2]*v2[0]) - v1[0]*v2[2];

    out[2] = (v1[0]*v2[1]) - v1[1]*v2[0];

    

   //normalize(out);

}





// This draws an axis....

void drawaxis(void)

{

        /* Draw first half of the line (j.k)*/

	glPushMatrix();

	glLineWidth(3.0);

        glBegin(GL_LINES);

		glColor4f(0.7,0.7,0.7,1.0);

		glVertex3f(    0.0,     0.0,     1.5);

		glVertex3f(    0.0,     0.0,     0.0);

	glEnd();



	/* draw second half of the lone, darker (j.k) */ 

	glBegin(GL_LINES);

		glColor4f(0.3,0.3,0.3,1.0);

		glVertex3f(    0.0,     0.0,     0.0);

		glVertex3f(    0.0,     0.0,     -1.5);

	glEnd();

	glPopMatrix();

	

	/* draw arrow "tip" as solid cone j.k. */

	glPushMatrix();

	 glColor4f(0.5,0.5,0.3,1.0);

	 glTranslatef( 0.0, 0.0, 1.5);

	 glutSolidCone(0.1, 0.2, 20.0, 20.0);

	glPopMatrix();







	/* before writing letters, move them in front  j.k.  */

	glPushMatrix();

	 glTranslatef(0.0,0.0, 0.2);

	 glColor4f(1.0,0.0,0.0,1.0);

	 glLineWidth(3.0);



	if(axe == 1)

	{

	    glBegin(GL_LINES);	

	     glVertex3f(  0.05,  0.05, 1.7);

	     glVertex3f( -0.05, -0.05, 1.7);



		 glVertex3f( -0.05,  0.05,  1.7);

		 glVertex3f(  0.05, -0.05,  1.7);

		glEnd();	



	  // glColor4f(0.2,1.0,0.0 ,1.0);

	  glTranslatef(0.0,0.0, 1.7);

	  glRotatef( SpiN,0.0,1.0,0.0 );



	  ZZ = gluNewQuadric();

	  gluQuadricDrawStyle(ZZ, GLU_FILL);

	  gluQuadricNormals(ZZ,GLU_SMOOTH);

	  gluDisk(ZZ, 0.1,0.15, 20.0, 20.0);

	}



	if(axe == 0)

	{

	glColor4f(0.0,1.0,0.0,1.0);

	  glBegin(GL_LINES);

	   glVertex3f(-0.05,-0.05, 1.7);

	   glVertex3f( 0.0,  0.0,  1.7);



	   glVertex3f( 0.05,-0.05, 1.7);

	   glVertex3f( 0.0,  0.0,  1.7);



	   glVertex3f( 0.0, 0.00, 1.7);

	   glVertex3f( 0.0, 0.05, 1.7);

	  glEnd();



	  glTranslatef(0.0,0.0, 1.7);

	  glRotatef( SpiN,0.0,1.0,0.0 );



	  // This is where the disk is drawn j.k.

	  ZZ = gluNewQuadric();

	  gluQuadricDrawStyle(ZZ, GLU_FILL);

	  gluQuadricNormals(ZZ,GLU_SMOOTH);

	  gluDisk(ZZ, 0.1,0.15, 20.0, 20.0);

	

	}

	

	

	if(axe == 2 )

	  {

 

	 glColor4f(0.0,0.0,1.0,1.0);

         glPushMatrix();



		  glBegin(GL_LINES);

	       glVertex3f( 0.05, 0.05, 1.7);

	       glVertex3f(-0.05, 0.05, 1.7);



	       glVertex3f( 0.05, 0.05, 1.7);

	       glVertex3f(-0.05,-0.05, 1.7);



	       glVertex3f( 0.05, -0.05, 1.7);

	       glVertex3f(-0.05, -0.05, 1.7);

	      glEnd();

    	glPopMatrix();

	

		glTranslatef(0.0,0.0, 1.7);

		glRotatef( SpiN,0.0,1.0,0.0 );



		  ZZ = gluNewQuadric();

		  gluQuadricDrawStyle(ZZ, GLU_FILL);

		  gluQuadricNormals(ZZ,GLU_SMOOTH);

		  gluDisk(ZZ, 0.1,0.15, 20.0, 20.0);

  }

	glPopMatrix();	

}





// Glut display callback....

void Display(void)

{

	int i, j, k, l;



    // hold the max values for x,y, and z

    int maxz = 0;

    int maxx = 0;

    int maxy = 0;

    int m = 0 ;



    GLfloat d, x, y, v1[3], v2[3], v3[3],v4[3];

    GLfloat normal[3], normal1[3], normal2[3];

    GLfloat normal3[3], normal4[3];

    GLfloat objectColor[] =    { 0.0, 0.5, 1.0, 1.0};

    GLfloat objectColorEnd[] = { 0.0, 0.0, 1.0, 1.0};



    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

       

    // Call current functions display list

    glCallList(dispList);

    glPushMatrix();

    

    // Set view...

    glRotatef(spinY, 1.0, 0.0, 0.0);

    glRotatef(spinX, 0.0, 1.0, 0.0);

    glRotatef(spinZ, 0.0, 0.0, 1.0);

	



    for (j=1; j < POINTSPERSIDE; j++)

      {

	for (i=min; i < max; i++)

	  {

	    for(l=1; l < POINTSPERSIDE; l++)

	      {



			glEnable(GL_COLOR_MATERIAL);

			glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);



		if(mode != 0)     

		  for (m = 0;m<199;m++)

		    {

		      v1[0] = (Coil[m].x - Coil[m+1].x);

		      v1[1] = (Coil[m].y - Coil[m+1].y);

		      v1[2] = (Coil[m].z - Coil[m+1].z);

		      

		      v2[0] = (Coil[m].x - p[j][i][l].x);

		      v2[1] = (Coil[m].y - p[j][i][l].y);

		      v2[2] = (Coil[m].z - p[j][i][l].z);

		      

		      normCrossProd(v1, v2, normal1);

		      

		      d = (v2[0]*v2[0]+v2[1]*v2[1]+v2[2]*v2[2]);

		      

		      if (mode == 2)

			d *= 80;

		      if (mode == 1)

			d *= 20;

		      

		      if(d > 0.001)

			{

			  normal1[0] /=d;

			  normal1[1] /=d;

			  normal1[2] /=d;

			}

		      if(mode == 2)

			if(d < 50)

			  {

			    normal[0] += normal1[0];

			    normal[1] += normal1[1];

			    normal[2] += normal1[2];

			  }

		      

		      if (mode == 1)

			if(d < 30)

			  {

			    normal[0] += normal1[0];

			    normal[1] += normal1[1];

			    normal[2] += normal1[2];

			  }

		    }

		else

		  {

		    

		    v1[0] = (0 - pcx);

		    v1[1] = (0 - pcy);

		    v1[2] = (0 - 0);

		    v2[0] = (0 - p[j][i][l].x);

		    v2[1] = (0 - p[j][i][l].y);

		    v2[2] = (0 - p[j][i][l].z);

		    

		    d = (v2[0]*v2[0]+v2[1]*v2[1]+v2[2]*v2[2]);

		    d *= 30;

		    

		    normCrossProd(v1, v2, normal);

		    if(d > 0.1)

		      {

			normal[0] /=d;

			normal[1] /=d;

			normal[2] /=d;

		      }

		  }

		

		glBegin(GL_LINES);

  		if(mode == 0)

		   glColor4f(0.0, 0.2, 0.2, 0.0);

		else

     	   glColor4f(0.0, 1.0, 1.0, 1.0);



			if(!(j == 1 && l == 1))

				glVertex3f( p[j][i][l].x - (normal[0]),  

						p[j][i][l].y - (normal[1]), p[j][i][l].z - (normal[2])) ;

				

				if(mode == 0)

				  {

					glColor4f(0.0, 1.0, 1.0, 1.0);

				  }

				else

				  {

					 glColor4f(0.0,0.2,0.2,0.0);

				  }

			if(!(j == 1 && l == 1))

				glVertex3f( (p[j][i][l].x + (normal[0])) ,   

						(p[j][i][l].y + (normal[1])),  (p[j][i][l].z + (normal[2]))  );



				glEnd();

				

				normal[0] = 0.0;

				normal[1] = 0.0;

				normal[2] = 0.0;

		

			}

		}

      }

        

    glLineWidth(3.0);

    glBegin(GL_LINES);

    if(mode == 0)

      {

		glColor4f(1.0,0.5,0.2,1.0);

		glVertex3f( -pcx, -pcy, 0);			

		glVertex3f(  pcx,  pcy, 0);

	}

	else

	{

	

	

	for( i=0;  i< 199;i++)

	  {

	    glColor4f(1-((i+anim)%200)/200.0,0.0,0.0,1.0);

	    glVertex3f(    Coil[i].x,    Coil[i].y,     Coil[i].z);

	    glVertex3f(    Coil[i+1].x,     Coil[i+1].y,     Coil[i+1].z);

	  }

      }

    

    glEnd();

    glLineWidth(3.0);

    

    // if axes is true, draw the 3 axes...

    if(1)

      {

		glPushMatrix();

		drawaxis();   // Z axis

		axe = 1;

		glRotatef(90.0, 0.0, 1.0, 0.0);

		drawaxis();   //  X axis

		axe = 2;

		glRotatef(90.0, 1.0, 0.0, 0.0);

		drawaxis();  //  Y axis

		axe = 0;

		glPopMatrix();

      }

    

    glPopMatrix();

        

    // if 2 seconds have gone by, calculate the frame rate...

    

    if(t-ot>1)

      

      {

	

		fps = frames/2;

		ot = t;

		frames = 0;

		sprintf(s,"Point Charge Demo / FPS:%d",fps);

		glutSetWindowTitle(s);

		  }

    

		glFinish();

		glutSwapBuffers();  // This is for double buffered implimentations....

		frames++;

}



// Turn on light 0   j.k.

void EnableLight0(void) 

{ 

  glPushMatrix(); 

  

  glLightfv(GL_LIGHT0, GL_SPECULAR, white_light); 

  glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); 

  

  glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION,spot_direction);  

  glLightf (GL_LIGHT0, GL_SPOT_CUTOFF,100.0); 

  

  glEnable(GL_LIGHTING);       // Let there be light 

  glEnable(GL_LIGHT0);         // Turn on the light  

  glEnable(GL_DEPTH_TEST); 

  glPopMatrix(); 

} 



// Turn light 1  j.k.

void EnableLight1(void) 

{ 

GLfloat light1[] = { 0.1, 0.2, 0.0, 1.0 }; 

 

glPushMatrix(); 

 

	glLightfv(GL_LIGHT1, GL_DIFFUSE,  light1);  

	glLightfv(GL_LIGHT1, GL_POSITION, light_position1); 

 

	glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION,spot_direction);  

	glLightf (GL_LIGHT1, GL_SPOT_CUTOFF,100.0); 

 

	glEnable(GL_LIGHTING);       // Let there be light 

	glEnable(GL_LIGHT1);         // Turn on the light  

	glEnable(GL_DEPTH_TEST); 

glPopMatrix(); 

} 



// Turn light 2  j.k.

void EnableLight2(void) 

{ 

 

glPushMatrix(); 

	glLightfv(GL_LIGHT2, GL_AMBIENT,  white_light);  

	glLightfv(GL_LIGHT2, GL_POSITION, light_position2); 

 

	glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION,spot_direction);  

	glLightf (GL_LIGHT2, GL_SPOT_CUTOFF,100.0); 

 

	glEnable(GL_LIGHTING);       // Let there be light 

	glEnable(GL_LIGHT2);         // Turn on the light  

	glEnable(GL_DEPTH_TEST); 

glPopMatrix(); 

} 



// Inits a Display list for each function func

void initDisplayList(int func)

{

  int i, j, k, l;

  

  // hold the max values for x,y, and z

  int maxz = 0;

  int maxx = 0;

  int maxy = 0;

  GLfloat d, x, y, v1[3], v2[3], v3[3],v4[3], normal[3], normal1[3], normal2[3], normal3[3], normal4[3];

  

  for (y=STARTCOORD, j=0; j<POINTSPERSIDE; y-=LENEDGE, j++)

    {

      for (x=-STARTCOORD, k=0; k<POINTSPERSIDE; x+=LENEDGE, k++)

	{

	  for ( z = -STARTCOORD, l=0; l<POINTSPERSIDE; z+=LENEDGE, l++)

	    {

	      p[k][j][l].x = x;

	      p[k][j][l].y = y;

	      

	      p[k][j][l].z = z;

	    }

	  

	}

    }

  

  glNewList(PointChargeList, GL_COMPILE);
  glBegin(GL_LINES);
  glColor4f(1.0,1.0,0.0,1.0);
  glVertex3f(    0,     0,     0);
  glVertex3f(    1,     1,     0);
  glEnd();

  glEndList(); 

  // Create a new list with the specified function
  glNewList(dispList, GL_COMPILE);
  for (j=1; j < POINTSPERSIDE; j++)
    {
      for (i=1; i < POINTSPERSIDE; i++)
	{
	  for(l=1; l < POINTSPERSIDE; l++)
	    {
	      // Enable GL_COLOR_MATERIAL so we can easily change the color for each vertex
				glEnable(GL_COLOR_MATERIAL);
				glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
				glBegin(GL_LINE_STRIP);
				v1[0] = 2;
				v1[1] = 2;
				v1[2] = 0;
				v2[0] = p[j][i][l].x;
				v2[1] = p[j][i][l].y;
				v2[2] = p[j][i][l].z;
				normCrossProd(v1, v2, normal);
				d = sqrt(normal[0]*normal[0]+normal[1]*normal[1]+normal[2]*normal[2]);
				glColor4f(0.0,1.0,1.0,1.0);
				glVertex3f(    p[j][i][l].x,     p[j][i][l].y,     p[j][i][l].z);
				glColor4f(0.0, 0.0, 0.0, 1.0);
				glEnd();
			}
		}
    }
    glEndList(); 

}


void init(void)
{   

    int i=0;



    // Use black as clear color...

    glClearColor(0.2,0.2,0.2,1.0);

	spinZ = 180.0;

	spinY = 45.0;

	spinX = 45.0;



    glClear(GL_COLOR_BUFFER_BIT);

    glShadeModel(GL_SMOOTH);



    glEnable(GL_BLEND);

    glEnable(GL_DEPTH_TEST);



    glMaterialfv(GL_FRONT, GL_SPECULAR,  matSpecular );

    glMaterialfv(GL_FRONT, GL_SHININESS, matShininess);

    

    EnableLight0(); 

    EnableLight1();  
    EnableLight2();
   initDisplayList(0);
  }

void reshape(int w, int h)
{
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glTranslatef(0.0, 0.0, -4.5); 
}

void Motion(int xPos, int yPos)
{
  if(spin == 0)
    {
      pcx = (GLfloat) (-(xPos)+400)/80;    
      pcy = (GLfloat) (yPos-400)/60;  
  }
  else
    {
      spinX = (GLfloat)-xPos;
      spinY = (GLfloat)-yPos;
    }
  oldx = xPos;
  oldy = yPos; 
}

// This menu function activated by the mouse button.  Modified j.k.
void menu(int m)
{
  switch(m)
    {
    case 1:
      glutFullScreen();
      glutPositionWindow(0,0);
      break;
    case 2:
      glutReshapeWindow(500, 500);
      glutPositionWindow(100,100);
      break;
    case 3:
      mode = 0;
	  if(spin)
		spin = 0;
      else
		spin = 1;
      break;
    case 4:
      mode = 1;
      break;
    case 5:
      mode = 2;
      break;  
    case 6:
      if(min == 1)
		min = 4;
      else
		min = 1;
      if(max == 8)
		max = 5;
      else
		max = 8;
      break;  
    case 7:
      if(incr == 2)
		incr = 0;
      else
		incr = 2;  
      break;
    case 8:
      //exit(0);
	  break;
	case 9:
		Xx = 1;
		break;
	case 10:
		Yy = 1;
		break;
	case 11:
		Zz = 1;
		break;
	case 12:
		Xx = Yy = Zz =0;
		break;
	default:
		glutReshapeWindow(500, 500);
		glutPositionWindow(100,100);
	break;
    }
}

// MUI callback function for buttons  j.k.
void readButton(muiObject *obj, enum muiReturnValue rv)
{ 
	if(obj == COIL) {
		mode = 2;
		spin = 1;
	}
	if(obj == PC) {
		mode = 0;
		if(spin)
			spin = 0;
		else
			spin = 1;
	}
	if(obj == ARC )
		{
			mode = 1;
			spin = 1;
		}
	if(obj == T3D )
	{
	 if(min == 1)
		min = 4;
     else
		min = 1;
     if(max == 8)
		max = 5;
     else
		max = 8;
	}
	if(obj == AN)
	{
	if(incr == 2)
		incr = 0;
     else
		incr = 2; 
	}
	if(obj == FS)
	{
		glutSetWindow( mW );
		glutFullScreen();
		glutPositionWindow(0,0);
	}
	if(obj == WM)
	{
		glutSetWindow( mW );
		glutReshapeWindow(500, 500);
		glutPositionWindow(100,100);
	}
	if(obj == RX)
			Xx = 1;
	if(obj == RY)
			Yy = 1;
	if(obj == RZ)
			Zz = 1;
	if(obj == SR)		
			Xx = Zz = Yy = 0;
//	if(obj == XX)
//		exit(0);
}

// Callback for the slider(s) j.k.
void readSliders(muiObject *obj, enum muiReturnValue rv) 
{
	glutPostRedisplay();
	rr = muiGetHSVal(SL);
	pcx = rr * 1.5;
	pcy = rr * -1.5 ;
	sprintf(rs,"POINT CHARGE %6.2f and %6.2f",pcx, pcy);
	muiChangeLabel(SLlabel, rs);
}

int main(int argc, char** argv)
{
	 // This is all pretty standard stuff to setup a window using glut. 
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(0,0);
    mW = glutCreateWindow("POINT CHARGE DEMO");
	// the menu is created and tied to the right mouse button  j.k.
	glutSetMenu(glutCreateMenu(menu));
    glutAddMenuEntry("FULL SCREEN MODE ", 1);
    glutAddMenuEntry("WINDOWED MODE ",   2);
    glutAddMenuEntry("POINT CHARGE ",    3);
    glutAddMenuEntry("ARC ",             4);
    glutAddMenuEntry("COIL ",            5);
    glutAddMenuEntry("TOGGLE 2D-3D ",    6);
    glutAddMenuEntry("ANIMATION ",       7);
    glutAddMenuEntry("ROTATE X",  9);
	glutAddMenuEntry("ROTATE Y", 10);
	glutAddMenuEntry("ROTATE Z", 11);
	glutAddMenuEntry("STOP ROTATION",   12);
//    glutAddMenuEntry("EXIT PROGRAM",     8);
    glutAttachMenu(GLUT_RIGHT_BUTTON);

	init();

    // Set glut callbacks...
    glutDisplayFunc(Display);
    glutReshapeFunc(reshape);
    glutMotionFunc(Motion);
    glutIdleFunc(Idle);
    dispList = 2;

  // This menu gets its own window.  It's MUI  j.k.
		glutInitWindowSize(300, 450);
		glutInitWindowPosition(600,0);
		muiWin = glutCreateWindow("CONTROLS"); /* window title */
        glutSetWindow( muiWin );
        muiInit();
        muiNewUIList(1);
        muiSetActiveUIList( 1 );
		// All the buttons and a slider created here. j.k.
		PC  = muiNewButton( 30,270,320,360);
		ARC = muiNewButton( 30,270,260,300);
		COIL= muiNewButton( 30,270,200,240);		
		FS  = muiNewButton( 20,130,150,180);
		WM  = muiNewButton(170,280,150,180);
		T3D = muiNewButton( 20,130,110,140);
		AN  = muiNewButton(170,280,110,140);
		RX  = muiNewButton( 10, 90, 70,100);
		RY  = muiNewButton(110,190, 70,100);
		RZ  = muiNewButton(210,290, 70,100);
		XX  = muiNewButton( 20,130, 10, 60);
		SR  = muiNewButton(170,280, 10, 60);
		SL  = muiNewHSlider(10,390,290,150,10);
		SLlabel = muiNewLabel(10, 420, rs);
		// Load the object created above j.k.
		muiLoadButton( COIL,"COIL MODE");
		muiLoadButton( ARC,"ARC MODE");
		muiLoadButton( PC, "POINT CHARGE MODE");
		muiLoadButton( FS, "FULL SCREEN");
		muiLoadButton( WM, "WINDOW MODE");
		muiLoadButton( T3D,"TOGGLE 2D-3D");
		muiLoadButton( AN, "ANIMATION");
		muiLoadButton( RY, "ROTATE Y");
		muiLoadButton( RX, "ROTATE X");
		muiLoadButton( RZ, "ROTATE Z");
		muiLoadButton( SR, "STOP ROTATION");
        muiLoadButton( XX, "EXIT PROGRAM");
		// Initialize callbacks j.k.
		muiSetCallback(COIL,readButton);
		muiSetCallback( ARC,readButton);
		muiSetCallback( PC, readButton);
	    muiSetCallback( FS, readButton);
	    muiSetCallback( WM, readButton);		
		muiSetCallback( T3D,readButton);
		muiSetCallback( AN, readButton);
		muiSetCallback( RY, readButton);
		muiSetCallback( RX, readButton);
		muiSetCallback( RZ, readButton);
		muiSetCallback( XX, readButton);
		muiSetCallback( SR, readButton);
		muiSetCallback( SL, readSliders);
		// Finally, add the objects to the list j.k.
		muiAddToUIList( 1,COIL);
		muiAddToUIList( 1, ARC);
		muiAddToUIList( 1, PC );
		muiAddToUIList( 1, FS );
		muiAddToUIList( 1, WM );
		muiAddToUIList( 1, T3D);
		muiAddToUIList( 1, AN );
		muiAddToUIList( 1, RY );
		muiAddToUIList( 1, RZ );
		muiAddToUIList( 1, RX );
		muiAddToUIList( 1, SR );
		muiAddToUIList( 1, XX );
		muiAddToUIList( 1, SL );

   // Main Loop!
    glutMainLoop(); //Main loop is ALWAYS at the end j.k.
    return 0;
}