/*
	Previewer cum Scene Modeler using of Radiance Input format.
	USAGE : <program> [options] <Radiance Input File>
	Options : 
		-s window_x_size window_y_size.
		-p window_x_posn window_y_posn.
		-v ONE/FOUR
		-c n ........For Circle Drawing Precision.
------
sumant (sumant@ncst.ernet.in)
*/

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include "preview.h"

FILE	*fp;
char	*program_name;
char	filename[80];

/*
 * Default Environment Values.
 */
int	circle_precision = 12; /* Circle Drawing Precision */
int	window_x_size=640, window_y_size=640;
int	window_x_posn=0, window_y_posn=0;
int	view_type = ONE;
int	oneview_flag = FRONT;
int	autorefresh_flag = ON;
int	modify_flag = OFF;
float	eyepoint_distance=10;

usage()
{
	fprintf(stderr, "usage: %s [-options] Radfile\n",program_name);
	fprintf(stderr,"options :\n");
	fprintf(stderr,"\t-c circle_precision. Default %d.\n",circle_precision);
	fprintf(stderr,"\t-p window_x_posn window_y_posn. Default %d %d.\n",
		window_x_posn,window_y_posn);
	fprintf(stderr,"\t-s window_x_size window_y_size. Default %d %d.\n",
		window_x_size,window_y_size);
	fprintf(stderr,"\t-v ONE/FOUR. View type Default %s.\n",
			(view_type==ONE)?"ONE":"FOUR");
	exit(1);
}

parse(argc, argv)
         int     argc;
         char    **argv;
{
	int	c=1;

	program_name = argv[0];
	
	while((c < argc)&&(argv[c][0]=='-')){
		int ch = argv[c][1]; c++;
		switch (ch){
		case 'c':
		case 'C': /* Circle Precision */
			if (c < argc){
				circle_precision = atoi(argv[c++]); 
				fprintf(stderr,
					"Circle is Displayed as %d sided Polygon.\n",
					circle_precision);
			}
			else usage();
			break;
		case 'p':
		case 'P': /* Window Position */
			if (c < argc){
				window_x_posn = atoi(argv[c++]);
				if (c < argc)
					window_y_posn = atoi(argv[c++]);
				else usage();
			}
			else usage();
			fprintf(stderr,
				"window x posn : %d, window y posn : %d.\n",
				window_x_posn,window_y_posn);
			break;
		case 's':
		case 'S': /* Window Size */
			if (c < argc){
				window_x_size = atoi(argv[c++]); 
				if (c < argc) window_y_size = atoi(argv[c++]);
				else usage();
			}
			else usage();
			fprintf(stderr,
				"window width : %d, window height : %d.\n",
				window_x_size,window_y_size);
			break;
		case 'v':
		case 'V': /* View Type */
			if (c < argc){
				capitalise(argv[c]);
				if (strcmp(argv[c],"ONE")==0)
					view_type=ONE;
				else if (strcmp(argv[c],"FOUR")==0)
					view_type=FOUR;
				else usage();
				c++;
			}
			else usage();
			fprintf(stderr,
				"%d View%s.\n",view_type,(view_type == FOUR)?"s":"");
			break;
		default : fprintf(stderr,"Wrong Option %s.");
			break;
		}
	}
	if (c < argc) strcpy(filename,argv[c++]);
	else usage();
}
help()
{
	fprintf(stderr,"Commands Available are :\n");
	fprintf(stderr,"\tr...For refreshing the screen.\n");
	fprintf(stderr,"\tn <filename>...To change the current file to a new file.\n");
	fprintf(stderr,"\t\tThe current file is %s.\n",filename);
	fprintf(stderr,"\tc <circle_precision>...To change the number of lines in which a circle is drawn.\n");
	fprintf(stderr,"\t\tCurrent circle precision is %d.\n",circle_precision);
	fprintf(stderr,"\tv <ONE/FOUR>...To choose either one view or four views.\n");
	fprintf(stderr,"\t\tCurrent View type default is %s.\n",
			(view_type==ONE)?"ONE":"FOUR");
	fprintf(stderr,"\ts <Flag> <Value>... To specify some global flag settings.\n");
	fprintf(stderr,"\t\tFollowing flags supported.\n");
	fprintf(stderr,"\t\t\tAUTOREFRESH... Values are ON/OFF.\n");
	fprintf(stderr,"\t\t\t\tCurrent Default value : %s.\n",
				(autorefresh_flag==ON)?"ON":"OFF");
	fprintf(stderr,"\t\t\tONEVIEW... Values are FRONT/SIDE/TOP/ISO/PER.\n");
	fprintf(stderr,"\t\t\t\tCurrent Default value : %s.\n",
			(oneview_flag==FRONT)?"FRONT":
			(oneview_flag==SIDE)?"SIDE":
			(oneview_flag==TOP)?"TOP":
			(oneview_flag==ISO)?"ISO":"PER");
}
draw_partition()
{
        color(WHITE);
        Xdraw(window_x_size/2,0,window_x_size/2,window_y_size);
        Xdraw(0,window_y_size/2,window_x_size,window_y_size/2);
}
freearg(arg)
FUNARGS *arg;
{
	int i;
	for(i=0;i<arg->nsargs;i++)
		if (arg->sarg[i]!=NULL)
			free((void *)arg->sarg[i]);
	if (arg->iarg!=NULL)
		free((void *)arg->iarg);
	if (arg->farg!=NULL)
		free((void *)arg->farg);
}
cleanup()
	/* Clean up the data structure by freeing the
	   allocated memory. 
	   Setting 
		nobjects=nmodifiers=0
	*/
{
	int i;
	bound_min_x=bound_min_y=bound_min_z=LARGE;
		bound_max_x=bound_max_y=bound_max_z= -LARGE;
	for(i=0;i<nobjects;i++){
		if (obj[i].onam!=NULL)
			free((void *)obj[i].onam);
		freearg(&(obj[i].oargs));
	}
	for(i=0;i<nmodifiers;i++){
		if (modifier_table.mnames[i]!=NULL)
			free((void *)modifier_table.mnames[i]);
		freearg(&(modifier_table.margs[i]));
	}
	nobjects=nmodifiers=0;
}
redraw()
{
	color(BLACK);
	clear(0,0,window_x_size,window_y_size);
	if (view_type == FOUR) draw_partition();
	drawobj(filename);
	modify_flag = OFF;
}
capitalise(s)
char *s;
{
	int i,n=strlen(s);
	for(i=0;i<n;i++)
		if (isalpha(s[i]) && islower(s[i]))
			s[i]=toupper(s[i]);
}
main(argc, argv)
	int	argc;
	char	**argv;
{
	char s[120];
	char command[80];
	int 	done=0;

	parse(argc, argv);
	initX(window_x_posn,window_y_posn,window_x_size,window_y_size); 
        if (view_type == FOUR)draw_partition();

	nobjects=0;
	if (readobj(filename)==0)
		fprintf(stderr,"New Scene File.\n");
	else {
		fprintf(stderr,
			"Screen Bounds <%g %g %g> to <%g %g %g>.\n",
						bound_min_x,
						bound_min_y,
						bound_min_z,
						bound_max_x,
						bound_max_y,
						bound_max_z);
		set_screen_transformation(
			bound_min_x,bound_max_x,
			bound_min_y,bound_max_y,
			bound_min_z,bound_max_z);
		drawobj();
	}
	do{
		fprintf(stderr,"----->"); gets(s);capitalise(s);
		switch(s[0]){
		case 'N':{
			char newfilename[80];
			if (sscanf(s,"%s%s",command,newfilename)==2){
				if (strcmp(newfilename,filename)!=0){
					strcpy(filename,newfilename);
					fprintf(stderr,"New File %s.\n",filename);
					modify_flag = ON;
					cleanup();
					if (readobj(filename)==0)
						fprintf(stderr,
						   "New Scene File.\n");
					else {
						fprintf(stderr,
						"Screen Bounds <%g %g %g> to <%g %g %g>.\n",
						bound_min_x,
						bound_min_y,
						bound_min_z,
						bound_max_x,
						bound_max_y,
						bound_max_z);
					set_screen_transformation(
						bound_min_x,bound_max_x,
						bound_min_y,bound_max_y,
						bound_min_z,bound_max_z)
					;
					}
					if (autorefresh_flag) redraw();
				}
				else fprintf(stderr,"Same file.\n");
			}
			else fprintf(stderr,"Missing File name.\n");
			}
			break;
		case 'C':{
			int n;
			if ((sscanf(s,"%s%d",command,&n)==2) && (n > 2)){
				if (n != circle_precision){
					circle_precision = n;
					modify_flag = ON;
					if (autorefresh_flag) redraw();
				}
			}
			else fprintf(stderr,"Wrong input for circle precision.\n");
			}
			break;
		case 'R': redraw(); break;
		case 'V':{
			char view[80];
			if (sscanf(s,"%s%s",command,view)==2){
				capitalise(view);
				if((strcmp(view,"ONE")==0)&&(view_type!=ONE)){
					view_type = ONE;
					redraw();
				}
				else if ((strcmp(view,"FOUR")==0)&&(view_type!=FOUR)){
					view_type = FOUR;
					redraw();
				}
				else fprintf(stderr,"Same or Wrong View specified.\n");
			}
			else fprintf(stderr,"View type missing.\n");
			}
			break;
		case 'Q':
			if(modify_flag)
			do{
				fprintf(stderr,"Want to redraw ? y/n : ");
				gets(s);capitalise(s);
				if (s[0] == 'Y'){
					redraw(); break;
				}
			}while (1);
			fprintf(stderr,"Want to quit ?  y/n : ");
			gets(s); capitalise(s);
			if (s[0] == 'Y') done = 1;
			break;
		case 'E':{
			char s[80];
			sprintf(s,"vi %s\n",filename);
			system(s);
			cleanup();
			readobj(filename);
			if (nobjects > 0){
			fprintf(stderr,
			"Screen Bounds <%g %g %g> to <%g %g %g>.\n",
						bound_min_x,
						bound_min_y,
						bound_min_z,
						bound_max_x,
						bound_max_y,
						bound_max_z);
			set_screen_transformation(
				bound_min_x,bound_max_x,
				bound_min_y,bound_max_y,
				bound_min_z,bound_max_z)
			;
			}
			modify_flag = ON;
			if (autorefresh_flag)redraw();
			}
			break;
		case 'S':{
			char type[80],value[80];
			sscanf(s,"%s%s%s",command,type,value);
			capitalise(type); capitalise(value);
			if(strcmp(type,"AUTOREFRESH")==0){
				if (strcmp(value,"ON")==0){
					if (autorefresh_flag!=ON){
						autorefresh_flag = ON;
						if (modify_flag==ON) redraw();
					}
				}
				else if (strcmp(value,"OFF")==0){
					if (autorefresh_flag!=OFF)
						autorefresh_flag = OFF;
				}
				else fprintf(stderr,"Wrong value.\nChoose from OFF/ON.\nCurrent value : %s\n",
					(autorefresh_flag==ON)?"ON":"OFF");
			}
			else if (strcmp(type,"ONEVIEW")==0){
				if (strcmp(value,"FRONT")==0){
					if (oneview_flag != FRONT){
						oneview_flag=FRONT;
						if (view_type == ONE)redraw();
					}
				}
				else if (strcmp(value,"SIDE")==0){
					if (oneview_flag != SIDE){
						oneview_flag=SIDE;
						if (view_type == ONE)redraw();
					}
				}
				else if (strcmp(value,"TOP")==0){
					if (oneview_flag != TOP){
						oneview_flag=TOP;
						if (view_type == ONE)redraw();
					}
				}
				else if (strcmp(value,"ISO")==0){
					if (oneview_flag != ISO){
						oneview_flag=ISO;
						if (view_type == ONE)redraw();
					}
				}
				else if (strcmp(value,"PER")==0){
					if (oneview_flag != PER){
						oneview_flag=PER;
						compute_perspective_matrix(
						bound_min_x,bound_max_x,
						bound_min_y,bound_max_y,
						bound_min_z,bound_max_z
						);
						if (view_type == ONE)redraw();
					}
				}
				else fprintf(stderr,"Wrong value.\nChoose from FRONT/SIDE/TOP/ISO/PER.\nCurrent value : %s\n",
					(oneview_flag==FRONT)?"FRONT":
					(oneview_flag==SIDE)?"SIDE":
					(oneview_flag==TOP)?"TOP":
					(oneview_flag==ISO)?"ISO":"PER");
			}
			else fprintf(stderr,"Wrong Setting specified.\nChoose from ONEVIEW/AUTOREFRESH.\n");
			}
			break;
		default : help(); break;
		}
	}while(!done);
	deinitX();
}
error(s,name)
char    *s,*name;
{
        fprintf(stderr, "%s: %s\n", name, s);
        exit(1);
}
warn(s,name)
char    *s,*name;
{
        fprintf(stderr, "%s: %s\n", name, s);
}
