/* isosurf.c */

/*
 * Display an isosurface of 3-D wind speed volume.  Use arrow keys to
 * rotate, S toggles smooth shading, L toggles lighting
 * Brian Paul
 */


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "EZ.h"


int speed_test = 0;

int doubleBuffer = 1;

int smooth = 1;
int lighting = 1;
float scale = 1.0;


#define MAXVERTS 10000

static float verts[MAXVERTS][3];
static float norms[MAXVERTS][3];
static int numverts;

static float xrot;
static float yrot;



static void read_surface(filename )
     char *filename ;
{
   FILE *f;

   f = fopen(filename,"r");
   if (!f) {
      printf("couldn't read %s\n", filename);
      exit(1);
   }

   numverts = 0;
   while (!feof(f) && numverts<MAXVERTS) {
      fscanf( f, "%f %f %f  %f %f %f",
	      &verts[numverts][0], &verts[numverts][1], &verts[numverts][2],
	      &norms[numverts][0], &norms[numverts][1], &norms[numverts][2] );
      numverts++;
   }
   numverts--;

   printf("%d vertices, %d triangles\n", numverts, numverts-2);
   fclose(f);
}



static void draw_surface()
{
  int i, j, k;

  EZ_Begin( EZ_TRIANGLE_STRIP );
  for (i=0;i<numverts;i++) {
    EZ_Normal3fv( norms[i] ); 
    EZ_Vertex3fv( verts[i] );
  }
  EZ_End();
}



static void draw1(void)
{
  EZ_Clear( EZ_COLOR_BUFFER_BIT | EZ_DEPTH_BUFFER_BIT );
  EZ_PushMatrix();
  EZ_Rotate( yrot, 0.0, 1.0, 0.0 );
  EZ_Rotate( xrot, 1.0, 0.0, 0.0 );
  EZ_Scale( scale, scale, scale);
  draw_surface();

  EZ_PopMatrix();

  if(doubleBuffer) 
    {
      EZ_SwapBuffers();
    }
}


static void draw()
{
  if(speed_test) 
    {
      for (xrot=0.0;xrot<=90.0;xrot+=1.0) 
	{
	  yrot++;
	  draw1();
	}
      exit(0);
    }
  else 
    {
      draw1();
    }
}


static void InitMaterials()
{
    static float ambient[] = {0.1, 0.1, 0.1, 1.0};
    static float diffuse[] = {0.9, 1.0, 1.0, 1.0};
    static float diffuse1[] = {.0, 1.0, 1.0, 1.0};
    static float position0[] = {2.7, 2.7, 2.7, 0.0};
    static float spot_dir[] = {-0.2, -0.2, -1.0, 0.0};
    static float spotE[] = {10.0};
    static float spotC[] = {6.0};

    static float position1[] = {-2.7, -2.7, -2.7, 0.0};
    static float front_mat_shininess[] = {60.0};
    static float front_mat_specular[] = {1., 1., 1., 1.0};
    static float front_mat_diffuse[] = {0.9, 0.28, 0.38, 1.0};
    static float back_mat_shininess[] = {3.0};
    static float back_mat_specular[] = {1., 1., 1., 1.0};
    static float back_mat_diffuse[] = {1.0, 1.0, 0.2, 1.0};
    static float lmodel_ambient[] = {1.0, 1.0, 1.0, 1.0};
    static float lmodel_twoside[] = {0.0};

    EZ_Lightfv(EZ_LIGHT0, EZ_AMBIENT, ambient);
    EZ_Lightfv(EZ_LIGHT0, EZ_DIFFUSE, diffuse);
    EZ_Lightfv(EZ_LIGHT0, EZ_POSITION, position0);

    EZ_Enable(EZ_LIGHT0);
    
    EZ_Lightfv(EZ_LIGHT1, EZ_AMBIENT, ambient);
    EZ_Lightfv(EZ_LIGHT1, EZ_DIFFUSE, diffuse1);
    EZ_Lightfv(EZ_LIGHT1, EZ_POSITION, position1);
    EZ_Enable(EZ_LIGHT1);
    
    EZ_LightModelfv(EZ_LIGHT_MODEL_AMBIENT, lmodel_ambient);
    EZ_LightModelfv(EZ_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
    EZ_Enable(EZ_LIGHTING);

    EZ_Materialfv(EZ_FRONT_AND_BACK, EZ_SHININESS, front_mat_shininess);
    EZ_Materialfv(EZ_FRONT_AND_BACK, EZ_SPECULAR, front_mat_specular);
    EZ_Materialfv(EZ_FRONT_AND_BACK, EZ_DIFFUSE, front_mat_diffuse);
}


static void Init()
{
   EZ_ClearColorf(0.0, 0.0, 0.0, 0.0);

   EZ_ShadeModel(EZ_SMOOTH);
   EZ_Enable(EZ_DEPTH_TEST);
   InitMaterials();
   EZ_MatrixMode(EZ_PROJECTION);
   EZ_LoadIdentity();
   EZ_Frustum( -1.0, 1.0, -1.0, 1.0, 5., 35. );

   EZ_MatrixMode(EZ_MODELVIEW);
   EZ_LoadIdentity();
   EZ_Translate( 0.0, 0.0, -6.0 );

   if(doubleBuffer) 
     EZ_DrawBuffer(EZ_BACK);
}

static int ppp = 0;

static void  event_handle(widget, cdata, event, xev)
     EZ_Widget *widget; void *cdata;
     int       event; XEvent *xev;
{
  if(event == EZ_REDRAW)
    draw();
  else if(event == EZ_KEY_PRESS)
    {
      switch(EZ_PressedKey) 
	{
	case EZ_ESCAPE_KEY:
	  EZ_Shutdown(); exit(0);
	  break;
	case EZ_LEFT_KEY:
	  yrot -= 15.0;
	  break;
	case EZ_RIGHT_KEY:
	  yrot += 15.0;
	  break;
	case EZ_UP_KEY:
	  xrot += 15.0;
	  break;
	case EZ_DOWN_KEY:
	  xrot -= 15.0;
	  break;
	case 'g':
	  smooth = !smooth;
	  if (smooth) {
	    EZ_ShadeModel(EZ_SMOOTH);
	  } else {
	    EZ_ShadeModel(EZ_FLAT);
	  }
	  break;
	case 's':
	  scale *= 1.1;
	  break;
	case 'a':
	  scale *= 0.9;
	  break;
	case 'l':
	  lighting = !lighting;
	  if (lighting) {
	    EZ_Enable(EZ_LIGHTING);
	  } else {
	    EZ_Disable(EZ_LIGHTING);
	  }
	  break;
	case 'p':
	  ppp = !ppp;
	  if(ppp) EZ_PolygonMode(EZ_FRONT_AND_BACK, EZ_LINE);
	  else EZ_PolygonMode(EZ_FRONT_AND_BACK, EZ_FILL);
	  break;
	default:
	  break;
	}
      draw();
    }
}



static int Args(argc, argv)
     int argc; char **argv;
{
  int i;

   for (i = 1; i < argc; i++) {
      if (strcmp(argv[i], "-sb") == 0) {
         doubleBuffer = 0;
      }
      else if (strcmp(argv[i], "-db") == 0) {
         doubleBuffer = 1;
      }
      else if (strcmp(argv[i], "-speed") == 0) {
         speed_test = 1;
	 doubleBuffer = 0;
      }
      else {
	printf("%s (Bad option).\n", argv[i]);
	return 0;
      }
   }
   return 1;
 }



void main(int argc, char **argv)
{
  EZ_Widget *canvas;
  char *extensions;
  
  read_surface( "isosurf.dat" );

  Args(argc, argv);

  EZ_Initialize(argc, argv, 1);
  canvas = EZ_Create3DCanvas(NULL);
  EZ_ConfigureWidget(canvas, EZ_WIDTH, 400, EZ_HEIGHT, 400, 
		     EZ_EVENT_HANDLE, event_handle, NULL,0);
  EZ_DisplayWidget(canvas);
  EZ_RGBMode();
  EZ_AutoSelectBackBuffer();
  EZ_Enable(EZ_DITHER);

  Init();
  draw();
  EZ_EventMainLoop();
}
