/*
 * National Center for Supercomputing Applications, University of Illinois
 *
 * This NCSA software product is public domain software.  Permission
 * is hereby granted to do whatever you like with it. Should you wish
 * to make a contribution towards the production of this software, please
 * send us your comments about your experience with the software,  why
 * you liked or disliked it, how you use it, and most importantly, how it
 * helps your work. We will receive your comments at softdev@ncsa.uiuc.edu.
 *
 * Please send bug reports to bugs@ncsa.uiuc.edu
 *
 *	Author:		Brian Calvert, NCSA
 *			bcalvert@ncsa.uiuc.edu
 */

/*
 *      File:           pvmain.c
 *      Contents:       Main code and general-purpose routines
 */

/*
	POLYVIEW 1.02
	National Center for Supercomputing Applications
	University of Illinois at Urbana-Champaign
*/


/* INCLUDE FILES */
#include "pv.h"


/* Global variables */
int quit_m;		/* Menu ids for window menus */
int vrender_m;
int vshade_m;
int voverlay_m;
int vproject_m;
int vpalette_m;
int vview_m;
int vanimate_m;
int view_m;

int nvert = 4;		/* Number of vertices per polygon (default 4) */
int quit = FALSE;	/* Time to quit the program? */

float scaling = 1.0;	/* Used for orthogonal scaling */
float max_width;	/* Maximum width of dataset */

float slope = 1.0;	/* Slope and  ... */
float origin = 0.0;	/* origin of color mapping function used by */
			/* "fiddling" feature in palette window */

short palette[256][3];		/* Active palette color values */
short master_palette[256][3];	/* Master palette color values */

Angle view_angle = 450;		/* Viewing angle */
Angle angle[DIMS] = {0, 0, 0};	/* Rotational angles around X, Y, & Z */
Angle twist = 0;		/* Viewing twist angle */
float	rho = 0;			/* Distance from origin */
float	theta = 0;			/* Azimuthal angle from x axis */
float	phi = 0;			/* Incident angle from z axis */

float step = 0.2;	/* Step size used for flights */

image_t main_image = {	/* The only image in the program  */
	"",
	"palette.raw",
	"ris8.hdf",
	"*",
	{"px", NULL},
	{"py", NULL},
	{"pz", NULL},
	{"plist4", NULL},
	{"scalar", NULL},
	NULL
};

state_t current = {NULL, 0, 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
		   FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE};

animation_t animation = {0, 0, 0, 1};

image_t * cur_image = NULL;	/* Pointer to currently displayed image */
image_t * images = NULL;	/* Pointer to images */
dataset_t * datasets = NULL;	/* Pointer to list of common datasets */
windat_t * windows = NULL;	/* Pointer to list of windows */
windat_t * title = NULL;	/* Pointer to title window */

/* Start up parameters */
char	flyfile[MAXPATHLEN] = "";	/* Name of flyfile */
float	from[3] = {0.0, 0.0, -2.0};	/* From point */
float	orig_from[3] = {0.0, 0.0, -2.0};/* From point */
float	at[3] = {0.0, 0.0, 0.0};	/* At point */


/* Command line switch definitions */
args_t args[] = {
       ARG_DEF("hdf", TRUE, STRING, MAXPATHLEN, main_image.fn,
               "the name of the HDF file to display"),
       ARG_DEF("palette", FALSE, STRING, MAXPATHLEN, main_image.palette,
               "the name of the palette file"),
       ARG_DEF("ris8out", FALSE, STRING, MAXPATHLEN, main_image.ris8out,
               "the name of the HDF RIS8 output file"),
       ARG_DEF("group", FALSE, STRING, MAXNAMELEN, main_image.group,
               "the name of the group to search for data"),
       ARG_DEF("fly", FALSE, STRING, MAXPATHLEN, flyfile,
               "the name of the fly file to use as course"),
       ARG_DEF("px", FALSE, STRING, MAXNAMELEN, main_image.p[X].name,
               "the name of the X-coordinate data set"),
       ARG_DEF("py", FALSE, STRING, MAXNAMELEN, main_image.p[Y].name,
               "the name of the Y-coordinate data set"),
       ARG_DEF("pz", FALSE, STRING, MAXNAMELEN, main_image.p[Z].name,
               "the name of the Z-coordinate data set"),
       ARG_DEF("connect", FALSE, STRING, MAXNAMELEN, main_image.connect.name,
               "the name of the connectivity data set"),
       ARG_DEF("scalar", FALSE, STRING, MAXNAMELEN, main_image.color.name,
               "the name of the color data set"),
       ARG_DEF("from", FALSE, FLOAT, 3, from,
               "the coordinate triple for the viewpoint"),
       ARG_DEF("axes", FALSE, BOOLEAN, 1, &current.axes,
               "tells the renderer to draw coordinate axes"),
       ARG_DEF("box", FALSE, BOOLEAN, 1, &current.box,
               "tells the renderer to draw bounding box"),
       ARG_DEF("constant", FALSE, BOOLEAN, 1, &current.constant,
               "sets the rendering method to CONSTANT (default GOURAUD)"),
       ARG_DEF("labels", FALSE, BOOLEAN, 1, &current.labels,
               "toggles whether labels are drawn on the data"),
       ARG_DEF("points", FALSE, BOOLEAN, 1, &current.points,
               "tells the renderer to draw data points on top of data"),
       ARG_DEF("lines", FALSE, BOOLEAN, 1, &current.lines,
               "tells the renderer to draw data as wireframe"),
       ARG_DEF("polygons", FALSE, BOOLEAN, 1, &current.polygons,
               "tells the renderer to draw data as polygons"),
       ARG_DEF("at_point", FALSE, BOOLEAN, 1, &current.at_point,
               "tells the renderer to draw a star at the AT point"),
       ARG_LAST
};


/* MAIN */
main (argc, argv)
	int argc;
	char * argv[];
{
	/* Parse the command-line arguments */
	args_parse(argc, argv, args);

	/* Create a pop-up menu for exit confimation */
	build_images(args, &images, &datasets);

	/* Open windows */
	open_windows(images, &windows);

	/* Initialize the image's viewing parameters for start-up */
	initialize(FALSE);

	/* Event handling */
	handle_events(windows);
}



void
initialize(reset)
	int reset;	/* TRUE if only resetting, FALSE if start-up */
/* DESCRIPTION:  Initializes the system's global variables based on user
parameters or defaults.  This routine modifies a lot of global variables!
*/
{
	image_t * image;
	float from_at_dist;
	double min[DIMS];
	double max[DIMS];
	int i;


	if (!reset) {
		/* Define the window pop-up menus */
		init_menus();

		/* Initialize events */
		init_events(windows);
	}

	/* Get the maxima and minima from the datasets so that we can */
	/* calculate viewing parameters using them. */
	image = (image_t *) images;
	for (i = 0; i < DIMS; i++) {
		max[i] = image->p[i].ds->max;
		min[i] = image->p[i].ds->min;

		/* Pick an "at" point */
		at[i] = (max[i] + min[i]) / 2;
	}

	/* Decide how many vertices per polygon we have */
	if (strcasecmp(main_image.connect.name, "plist3") == 0) {
		nvert = 3;
	}

	/* Build the colormap.  If a filename was specified, */
	/* attempt to open it and load the palette.  */
	/* Otherwise, use the default palette. */
	if (args_found_arg(args, "palette"))
		build_colormap(LOAD_SPEC);
	else
		build_colormap(RBOW_SPEC);

	if (reset) {
		from[X] = orig_from[X];
		from[Y] = orig_from[Y];
		from[Z] = orig_from[Z];
	}
	else {
		/* Pick a "from" point, if necessary.  Choose it to make a */
		/* 90 degree field of view. */
		if (!args_found_arg(args, "from")) {
			orig_from[X] = from[X] = at[X];
			orig_from[Y] = from[Y] = at[Y];
			orig_from[Z] = from[Z] = max[Z] * 1.1 +
			  	MAX((max[X] - min[X]), (max[Y] - min[Y]));
		}
	}

	/* Pick a viewing angle, if necessary. */
	max_width = fhypot(max[X] - min[X],
		    fhypot(max[Y] - min[Y], max[Z] - min[Z])) / 2.0;
	rho =
	from_at_dist = fhypot((at[X]-from[X]),
		       fhypot((at[Y]-from[Y]), (at[Z]-from[Z])));
	view_angle = (Angle) (3600.0/PI * fatan2(max_width, from_at_dist));

	/* Additional viewing parameters */
	scaling = 1.0;		/* Used for orthogonal scaling */
	slope = 1.0;		/* Slope and  ... */
	origin = 0.0;		/* origin of color mapping function used by */
				/* "fiddling" feature in palette window */
	twist = 0;		/* Viewing twist angle */
	cart_to_sphere(from[X]-at[X], from[Y]-at[Y], from[Z]-at[Z],
		       &rho, &theta, &phi);

	/* Reset animatrion parameters */
	animation.reverse = 0;
	animation.time_last_redraw = 0;
	animation.forward = 0;
	animation.speed = 1;

	/* If neither points nor lines are selected, set polygons. */
	if (!(current.points || current.lines)) {
		current.polygons = TRUE;
	}

	/* Reset flight parameters */
	step = 0.2;		/* Step size used for flights */
}


void
build_colormap(which_map)
	int	which_map;
/* DESCRIPTION:  build_colormap creates a SPEC_SIZE cell color spectrum.
"which_map" determines which colormap is generated.  Only RGB and GRAY are
supported at this point.  RGB_SPEC creates a red-togreen-to-blue spectrum.
GRAY_SPEC causes a white to black spectrum to be created.
*/
{
	int cellnum;	/* Color cell number being modified. */
	int i;	
	float r, g, b;	/* Color's red, green, and blue components (0..255) */
	float w;	/* Color's white component (0..255) */
	int x;		/* Mapped value for color "fiddling" */
	char red[256], blue[256], green[256];	/* character arrays that */
						/* contain palette rgb values */

	FILE *fp; /* palette file to be used */
	short ir, ig, ib; /* integers to hold the r, g, and b components */


	switch (which_map) {
	case RGB_SPEC:
		/* Initialize the color components for the "blue" end of the */
		/* spectrum */
		b = 255.0;
		g = r = 0.0;

		/* Full blue to full green, red constant */
		for (cellnum = SPEC_BLUE; cellnum <= SPEC_GREEN; cellnum++) {
			palette[cellnum][R] =  (short) r;
			palette[cellnum][G] = (short) g;
			palette[cellnum][B] = (short) b;
			b -= RGB_INCREMENT;
			g += RGB_INCREMENT;
		}

		/* Full green to full red, blue constant */
		for (; cellnum <= SPEC_RED; cellnum++) {
			palette[cellnum][R] =  (short) r;
			palette[cellnum][G] = (short) g;
			palette[cellnum][B] = (short) b;
			g -= RGB_INCREMENT;
			r += RGB_INCREMENT;
		}
		break;
	case GRAY_SPEC:
		/* Initialize the white component for the "black" end of */
		/* the spectrum. */
		w = 0.0;
		for (cellnum = SPEC_BLACK; cellnum <= SPEC_WHITE; cellnum++) {
			palette[cellnum][R] =  (short) w;
			palette[cellnum][G] = (short) w;
			palette[cellnum][B] = (short) w;
			w += GRAY_INCREMENT;
		}
		break;
	case LOAD_SPEC:
		if (args_found_arg(args, "palette")) {
			if ((fp = fopen(main_image.palette,"r")) != NULL) {
				/* Read in the raw palette from palette file */
				fread(red,1,256,fp);
				fread(green,1,256,fp);
				fread(blue,1,256,fp);
				fclose(fp);

				/* Copy colors into palette array for display */
				for (cellnum = 0; cellnum < 256; cellnum++) {
					palette[cellnum][R] =  (short)
								 red[cellnum];
					palette[cellnum][G] = (short)
								 green[cellnum];
					palette[cellnum][B] = (short)
								 blue[cellnum];
				}
			}
			else {
				printf("\nERROR:  '%s' cannot be opened.\n",
					main_image.palette);
			}
		}
		else {
			printf("\nPlease specify palette file on command \n");
			printf("line using the '-palette' switch for this \n");
			printf("option.\n");
		}

		break;
		
	case RBOW_SPEC:
		/* Use the default rainbow palette */
		/* Initialize the color components for the rainbow palette */
		r = 129.0;
		g = 0.0;
		b = 255.0;

		/* Violet to blue.  Green, blue constant, red changes */
		for (cellnum = 0; cellnum < 29; cellnum++) {
			palette[cellnum][R] =  (short) r;
			palette[cellnum][G] = (short) g;
			palette[cellnum][B] = (short) b;
			r -= (130.0/29.0);
		}
		r = 0.0;
		g = 2.036;

		/* Blue to light blue.  Red, blue constant, green changes */
		for (; cellnum < 86; cellnum++) {
			palette[cellnum][R] =  (short) r;
			palette[cellnum][G] = (short) g;
			palette[cellnum][B] = (short) b;
			g += (257.0/57.0);
		}
		g = 255.0;
		b = 251.5;

		/* Light blue to green.  Red, green constant, blue changes */
		for (; cellnum < 142; cellnum++) {
			palette[cellnum][R] =  (short) r;
			palette[cellnum][G] = (short) g;
			palette[cellnum][B] = (short) b;
			b -= (247.0/55.0);
		}
		b = 0.0;
		r = 1.27;

		/* Green to yellow.  Green, blue constant, red changes */
		for (; cellnum < 199; cellnum++) {
			palette[cellnum][R] =  (short) r;
			palette[cellnum][G] = (short) g;
			palette[cellnum][B] = (short) b;
			r += (252.5/56.0);
		}
		r = 255.0;
		g = 252.5;

		/* Yellow to red.  Red, blue constant, green changes */
		for (; cellnum < 256; cellnum++) {
			palette[cellnum][R] =  (short) r;
			palette[cellnum][G] = (short) g;
			palette[cellnum][B] = (short) b;
			g -= (252.0/56.0);
		}

		break;
	case MAP_SPEC:
		for (cellnum = 1; cellnum < 255; cellnum++) {
			/* Calculate the mapping function from the master */
			/* palette to the active palette */
			x =  (((float)cellnum - origin) / slope);
			if (x < 1) x = 1;
			if (x > 254) x = 254;
			
			palette[cellnum][R] = master_palette[x][R];
			palette[cellnum][G] = master_palette[x][G];
			palette[cellnum][B] = master_palette[x][B];
		}
		break;
	default:
		printf("\nERROR:  Unknown color map type.\n");
		break;
	}

	/* Set the end colors to white and black */
	palette[0][R] = palette[0][G] = palette[0][B] = 0;
	palette[255][R] = palette[255][G] = palette[255][B] = 255;

	/* Copy the palette into the system palette for display */
	/* And into the master palette array for reference */
	for (cellnum = 0; cellnum < 256; cellnum++) {
		mapcolor(cellnum+SPEC_BASE, palette[cellnum][R],
			palette[cellnum][G], palette[cellnum][B]);
		if (which_map != MAP_SPEC) {
			master_palette[cellnum][R] = palette[cellnum][R];
			master_palette[cellnum][G] = palette[cellnum][G];
			master_palette[cellnum][B] = palette[cellnum][B];

			slope = 1.0;
			origin = 0.0;
		}
	}

	return;
}


int
read_fly_file(filename)
{
	FILE * in_fp;
	char line[MAXLINELEN];


	/* Make sure that we can get the file */
	if ( (in_fp = fopen(filename, "r")) == NULL) {
		return TRUE;	/* ERROR! */
	}

	/* Do commands until we reach the end of the file. */
	while ( (!feof(in_fp)) && (current.fly_mode) ) {
		line[0] = '\0';

		/* Get a line from the file */
		fscanf(in_fp, "%[^\n;]", line);
		fscanf(in_fp, "%*[^\n]\n");
		fscanf(in_fp, "\n");

		/* Get the command word from the line and execute it */
		if (line[0] != '\0') {
			if (parse_and_exec(commands, line)) {
				printf("ERROR:\tParsing '%s':\n", filename);
				printf("\t%s\n", line);
			}
		}

		handle_event(windows);
	}

	fclose(in_fp);
	return FALSE;
}
