/*****************************************************************
 ***                                                           ***
 ***     objects.c                                              ***
 ***         EZ_Widget Lib Demo Program                        ***
 ***         Display internally defined simple objects         ***
 ***                                                           ***
 *****************************************************************/
#include "EZ.h"

#define Abs(x) ((x)> 0? (x): -(x))
extern void exit();
int   canvas_event_handle(); 
void  Show_Objects();
int   help_call_back();
int   hide_call_back();

static char help_title[] = "EZ_GL Demo: Internal Objects";
static char help_message[] = "Hit the 'a' or 's' key to zoom in or out\n\
Hit the 'f' or 'g' toggle flat or gouraud shading for polygons\n\
Hit 'c' or 'r' toggle to colormap or RGB mode\n\n\
Press and move the left button rotate the object about the picked axies";

/*****************************************************************************
 *
 *   Define three light sources.
 */
static EZ_LightSrc *Light1, *Light2, *Light3;

static float  light1[] = 
{
  EZ_POSITION_F, 1.0,0.0,2.0, 0.0,      
  EZ_DIFFUSE_F,  1.0,1.0,1.0,1.0,
  EZ_NULL_F,
};

static float  light2[] =
{
  EZ_POSITION_F,   0.0,5.0,10.0,1.0,
  EZ_SPECULAR_F,   1.0,1.0,1.0,1.0,     
  EZ_SPOT_DIRECTION_F, 0.0,0.0,-1.0,0.0,
  EZ_SPOT_CUTOFF_F,  30.0, 
  EZ_SPOT_EXPONENT_F, 10.0, 
  EZ_NULL_F,
};

static float  light3[] =
{  
  EZ_POSITION_F,  4.0,0.0,8.0, 1.0,      
  EZ_DIFFUSE_F,  1.0,1.0,0.0,1.0,
  EZ_SPECULAR_F, 1.0,1.0,0.0,1.0,     
  EZ_NULL_F,

};


void Define_Light_Sources()
{
  Light1 = EZ_DefineLight(light1);
  Light2 = EZ_DefineLight(light2);
  Light3 = EZ_DefineLight(light3);
}

void Bind_Light_Sources()
{
  EZ_BindLight(0, Light1);
  EZ_BindLight(1, Light2);
  EZ_BindLight(2, Light3); 
}
/*********************************************************************************/
static           EZ_Widget *help;
static EZ_Matrix RotationMatrix;
static float     scale = 1.0;
static float     tx = 0.0,ty = 0.0,tz= 0.0;
static float specular[] = {1.0,1.0,1.0,1.0};
static float shininess[] = {4.0};
static float colorindices[] = {60.0, 70.0,120.0};

static float aa[2] = { -44.0, 0};
static float bb[2] = { 10.0, 0};
static float cc[2] = { 4.0, 0};
static float fogc[4] = {0.8, 0.8,0.8,1.0};
static float fogd[1] = {8.0};
static float foge[1] = {(float)EZ_EXP};
static float fogs[1] = {0.3};
static float fogE[1] = {0.7};
static float cmapmode[3] = {16.0,100.0,130.0};


main(ac,av)
     int ac;
     char **av;
{
  EZ_Widget *canvas, *tmp, *fff;

  EZ_Initialize(ac,av,1);              /*    initialize the EZ library       */

  canvas = EZ_Create3DCanvas(NULL);    /*    create a graphics window        */
  EZ_ConfigureWidget(canvas,           /*    set the desired config options  */
		     EZ_WIDTH, 500,
		     EZ_HEIGHT,500, 
		     EZ_EVENT_HANDLE, canvas_event_handle, NULL,
		     EZ_SIDE, EZ_BOTTOM,
		     0);

  help = EZ_CreateFrame(NULL,"help");
  EZ_ConfigureWidget(help,
		     EZ_STACKING, EZ_VERTICAL, 
		     0);
  tmp = EZ_CreateLabel(help,help_title);
  EZ_ConfigureWidget(tmp,
		      EZ_FONT_NAME,  "-Adobe-Times-Bold-R-Normal--*-180-*-*-*-*-*-*",   
		      EZ_FOREGROUND, "red",
		      0);
  tmp = EZ_CreateLabel(help,help_message);
  EZ_ConfigureWidget(tmp,
		      EZ_TEXT_LINE_LENGTH, 80,
		      0);
  tmp = EZ_CreateButton(help,"Hide",1);
  EZ_ConfigureWidget(tmp,
		      EZ_CALL_BACK, hide_call_back, NULL,
		      0);
  
  tmp = EZ_CreateButton(canvas,"Help",0);
  EZ_ConfigureWidget(tmp,
		      EZ_CALL_BACK, help_call_back, NULL,
		      0);
  tmp = EZ_CreateButton(canvas,"Quit",0);
  EZ_ConfigureWidget(tmp,
		      EZ_CALL_BACK, exit, NULL,
		      0);
  
  EZ_DisplayWidget(canvas); 

  EZ_MatrixMode(EZ_PROJECTION);
  EZ_Ortho(-10.0,10.0,-10.0,10.0,-30.0,35.0);          /* set projection   */

  EZ_MatrixMode(EZ_MODELVIEW);

  EZ_AutoSelectBackBuffer();
  EZ_RGBMode();
  EZ_ClearColorf(0.8,0.8,0.8,1.0);
  EZ_ShadeModel(EZ_SMOOTH);
  EZ_DrawBuffer(EZ_BACK);
  
  Define_Light_Sources();
  Bind_Light_Sources(); 
  EZ_LightModelfv(EZ_LIGHT_MODEL_TWO_SIDE, bb);
  
  EZ_IdentityMatrix(RotationMatrix);
  EZ_Enable(EZ_DEPTH_TEST);
  EZ_Enable(EZ_LIGHTING);
  EZ_Enable(EZ_LIGHT0);
  EZ_Enable(EZ_LIGHT1);
  EZ_Enable(EZ_LIGHT2);

  EZ_Enable(EZ_FOG);

  EZ_Fogfv(EZ_FOG_COLOR,fogc);
  EZ_Fogfv(EZ_FOG_DENSITY,fogd);
  EZ_Fogfv(EZ_FOG_MODE,foge);
  EZ_Fogfv(EZ_FOG_START,fogs);
  EZ_Fogfv(EZ_FOG_END,fogE);
  EZ_Fogfv(EZ_FOG_INDEX,aa);


  /* EZ_Enable( EZ_CULL_FACE );*/
  EZ_Enable( EZ_COLOR_MATERIAL );
  EZ_Materialfv(EZ_FRONT,EZ_SPECULAR,specular);
  EZ_Materialfv(EZ_FRONT,EZ_SHININESS,shininess);
  EZ_Materialfv(EZ_FRONT,EZ_COLOR_INDICES,colorindices);
  /*  EZ_PolygonMode(EZ_FRONT,EZ_LINE);
  EZ_PolygonMode(EZ_BACK,EZ_FILL);*/

  Show_Objects();
  EZ_EventMainLoop();
}

/*******************************************************************************
 *
 *  Display a bunch of internally defined objects
 */
static float curve[20][4] =
{
  {1.000000, 0.000000, 0.0, 0.500000},
  {0.945817, 0.324699, 0.0, 0.494582},
  {0.789141, 0.614213, 0.0, 0.478914},
  {0.546948, 0.837166, 0.0, 0.454695},
  {0.245486, 0.969400, 0.0, 0.424549},
  {-0.082579, 0.996584, 0.0, 0.391742},
  {-0.401695, 0.915773, 0.0, 0.359830},
  {-0.677282, 0.735724, 0.0, 0.332272},
  {-0.879474, 0.475947, 0.0, 0.312053},
  {-0.986361, 0.164595, 0.0, 0.301364},
  {-0.986361, -0.164595, 0.0, 0.301364},
  {-0.879474, -0.475947, 0.0, 0.312053},
  {-0.677282, -0.735724, 0.0, 0.332272},
  {-0.401695, -0.915773, 0.0, 0.359830},
  {-0.082579, -0.996585, 0.0, 0.391742},
  {0.245486, -0.969400, 0.0, 0.424549},
  {0.546949, -0.837166, 0.0, 0.454695},
  {0.789141, -0.614212, 0.0, 0.478914},
  {0.945818, -0.324698, 0.0, 0.494582},
  {1.000000, 0.000002, 0.0, 0.500000},
};

static float ftt[] = {
-1.0, 0.0, 0.0, 0.0,
 0.0, 0.0, 0.0, 0.5,
 1.0, 0.0, 0.0, 1.0,
};

static float red[] = {1.0,0.0,0.0,1.0};
static float green[] = {1.0,0.0,0.0,1.0};
static float blue[] = {1.0,0.0,0.0,1.0};
static float yellow[] = {1.0,1.0,0.0,1.0};
static float cyan[] = {0.0,1.0,1.0,1.0};
static float pink[] = {1.0,0.0,1.0,1.0};

void Show_Objects()
{

  EZ_LoadIdentity();
  EZ_Translate(tx,ty,tz);
  EZ_MultMatrix(RotationMatrix);
  EZ_Scale(scale,scale,scale);

  EZ_Clear(EZ_COLOR_BUFFER_BIT|EZ_DEPTH_BUFFER_BIT);

  EZ_Materialfv(EZ_FRONT,EZ_DIFFUSE,red);
  EZ_Dodecahedron(-6.0,0.0,0.0,2.0);
  EZ_Materialfv(EZ_FRONT,EZ_DIFFUSE,green);
  EZ_Cube(6.0,0.0,0.0,2.0);
  EZ_Materialfv(EZ_FRONT,EZ_DIFFUSE,blue);
  EZ_Octahedron(0.0,-6.0,0.0,2.0);
  EZ_Materialfv(EZ_FRONT,EZ_DIFFUSE,cyan);
  EZ_Icosahedron(0.0,6.0,0.0,2.0);
  EZ_Materialfv(EZ_FRONT,EZ_DIFFUSE,yellow);
  EZ_Tetrahedron(0.0,0.0,6.0,2.0);
  EZ_Materialfv(EZ_FRONT,EZ_DIFFUSE,pink);
  EZ_Sphere(EZ_SPHERE_QUAD, 4,0.0,0.0,0.0,2.0); 
  EZ_Translate(0.0,0.0,-6.0);
  /*  EZ_Tube((float *)curve,20,8); */
  EZ_Tube(ftt,3,16);

  EZ_SwapBuffers();
}

/****************************************************************/
int canvas_event_handle(widget,data, event_type, xev)
     EZ_Widget   *widget; void *data;
     int         event_type; XEvent *xev;
{
  int redraw = 0;

  switch(event_type)
    {
    case EZ_REDRAW:
    case EZ_RESIZE:
      redraw = 1;
      break;
    case EZ_KEY_PRESS:
      switch(EZ_PressedKey)
	{
	case 's':
	  scale *= 1.1;
	  redraw = 1;
	  break;
	case 'a':
	  scale *= 0.9;
	  redraw = 1;
	  break;
	case 'g':
	  EZ_ShadeModel(EZ_SMOOTH);
	  redraw = 1;
	  break;
	case 'f':
	  EZ_ShadeModel(EZ_FLAT);
	  redraw = 1;
	  break;
	case 'r':
	  EZ_RGBMode();
	  EZ_ClearColorf(0.8,0.8,0.8,1.0);
	  redraw = 1;
	  break;
	case 'c':
	  EZ_ColorMapMode();
	  EZ_ClearIndex(0);
	  EZ_MakeColorMapForMaterial(NULL, 16,120);
	  redraw = 1;
	  break;
	case EZ_RIGHT_KEY:
	  {
	    EZ_Matrix mat,tmp;
	    EZ_GenerateRotationMatrix(mat,5.0,0.0,1.0,0.0);
	    EZ_MultiplyMatrix(tmp, RotationMatrix, mat);
	    EZ_CopyMatrix(RotationMatrix,tmp);
	    redraw = 1;
	  }
	  break;
	case EZ_LEFT_KEY:
	  {
	    EZ_Matrix mat,tmp;
	    EZ_GenerateRotationMatrix(mat,-5.0,0.0,1.0,0.0);
	    EZ_MultiplyMatrix(tmp, RotationMatrix, mat);
	    EZ_CopyMatrix(RotationMatrix,tmp);
	    redraw = 1;
	  }
	  break;
	case EZ_UP_KEY:
	  {
	    EZ_Matrix mat,tmp;
	    EZ_GenerateRotationMatrix(mat,-5.0,1.0,0.0,0.0);
	    EZ_MultiplyMatrix(tmp, RotationMatrix, mat);
	    EZ_CopyMatrix(RotationMatrix,tmp);
	    redraw = 1;
	  }
	  break;
	case EZ_DOWN_KEY:
	  {
	    EZ_Matrix mat,tmp;
	    EZ_GenerateRotationMatrix(mat,5.0,1.0,0.0,0.0);
	    EZ_MultiplyMatrix(tmp, RotationMatrix, mat);
	    EZ_CopyMatrix(RotationMatrix,tmp);
	    redraw = 1;
	  }
	  break;

	case EZ_ESCAPE_KEY:
	  EZ_GLExit();
	  exit(0);
	  break;
	default:
	  break;
	}
      EZ_GLResetEvents(NULL); 
      break;
    case EZ_LEFT_BUTTON_PRESS:
      {
	int ox = EZ_MouseX;
	int oy = EZ_MouseY;
	int nx, ny, device;
	
	while(1)
	  {
	    device = EZ_GLNextEvent(NULL, NULL); 
	    if(device == EZ_POINTER_MOTION)
	      {
		nx = EZ_MouseX;
		ny = EZ_MouseY;
		if( Abs(ox - nx) + Abs(oy - ny) > 10)
		  {
		    float axis[3], angle;
		    EZ_Matrix mat, tmp;
		    
		    axis[0] = (float) (oy - ny);
		    axis[1] = (float) (nx - ox);
		    axis[2] = 0.0;
		    angle = 0.1 *(Abs(axis[0]) + Abs(axis[1]));
		    EZ_GenerateRotationMatrix(mat,angle,axis[0],axis[1],axis[2]);
		    EZ_MultiplyMatrix(tmp, RotationMatrix, mat);
		    EZ_CopyMatrix(RotationMatrix,tmp);

		    Show_Objects();
		    ox = nx; oy = ny;
		  }
	      }
	    else if(device == EZ_LEFT_BUTTON_RELEASE)
	      break;
	  }
      }
      break;
    case EZ_RIGHT_BUTTON_PRESS:
      {
	int ox = EZ_MouseX;
	int oy = EZ_MouseY;
	int nx, ny, device;
	
	while(1)
	  {
	    device = EZ_GLNextEvent(NULL, NULL); 
	    if(device == EZ_POINTER_MOTION)
	      {
		nx = EZ_MouseX;
		ny = EZ_MouseY;
		if( Abs(ox - nx) + Abs(oy - ny) > 10)
		  {
		    tx += 0.02 *(nx - ox);
		    ty += 0.02 *(ny - oy);
		    Show_Objects();
		    ox = nx; oy = ny;
		  }
	      }
	    else if(device == EZ_RIGHT_BUTTON_RELEASE)
	      break;
	  }
      }
      break;
    default:
      break;
    }
  if(redraw)
    Show_Objects();

}

/*************************************************************************/
int   help_call_back(widget)
     EZ_Widget *widget;
{
  EZ_DisplayWidget(help);
}

int   hide_call_back(widget)
     EZ_Widget *widget;
{
  EZ_HideWidget(help);
}
/*************************************************************************/
