/* 
	A Filter to Convert Radiance(v 1.4) input file format
		to rad input file format.
	USAGE :
		radfilter [-option] < Radiance_input_filename > MC_input_filename
	The output is complete with surface information except the
	following.

	Options:
	--------
	-n <number> : The total number of Patches.
	-s : For creating output with special view parameters. 
		Default is simple Perspective view parameters.
------
sumant
*/
#include <stdio.h>
#include <math.h>
#include "preview.h"


#define MIN(a,b) (((a)>(b))?(b):(a))
#define MAX(a,b) (((a)>(b))?(a):(b))
extern int (*read_n_dumpobject[MAXPRIMITIVES])();
int max_pieces=1000;
#define SPL 0
#define PERSP 1
int view_type = PERSP;
main(argc,argv)
int argc;
char *argv[];
{
	int i=1;
	while (i<argc){
		if (argv[i][0] == '-')
		    switch (argv[i][1]){
		    case 'n':
			if (i+1 < argc){
			int num;
			sscanf(argv[++i],"%d",&num);
			if (num > 0) max_pieces = num;
			}
			break;
		    case 's':
			view_type = SPL;	
			break;
		    default : break;
		    }
		else break;
		i++;
	}
	readobj(NULL);
	fprintf(stderr,"Total Surfaces : %d\n",nobjects);
	fprintf(stderr,
		"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);
	fprintf(stderr,"Total surface area : %g\n",cum_area);
	dump_viewparameters();
	printf("3\n%d\n",nobjects);/*No. of channels & no. of objects.*/
	for(i=0;i<nobjects;i++)
		read_n_dumpobject[obj[i].otyp](
			obj[i].area,
			obj[i].otyp,
			obj[i].omod,
			obj[i].onam,
			&(obj[i].oargs));
	dump_subdivisions();
}

dump_viewparameters()
{
	if (view_type==SPL){
	printf("s\n"); /* View Type */
	printf("1\n"); /* No of Frames */
	printf("512 512\n"); /* Resolution */
	printf("53 53\n"); /* Start FOV and end FOV */
	printf("0 0 1\n"); /* path plane normal */
	printf("1\n"); /* Camera Horiz axis 
				0 - Against path
				1 - Along the path */
	printf("0 0\n"); /* Camera Vertical Offset.
				start and end */
	printf("1\n"); /* Type of path.
				0 - Linear
				1 - Circular */
	printf("%f %f %f\n", /* Origin of the Circle */
		(bound_min_x+bound_max_x)/2.,
		(bound_min_y+bound_max_y)/2.,
		(bound_min_z+bound_max_z)/2.);
	printf("%f\n",	/* Radius of the Circle */
		0.5*fabs(bound_max_x - bound_min_x)/tan(DTOR*27.));
	printf("270 270\n"); /* Start and end angles of
				the circular arc.
                                Angle 0 - Indicates viewing
                                     along the X-axis of the Camera.*/
	}
	else{ /* Simple perspective view specification */
	printf("v\n"); /* View Type */
	printf("512 512\n"); /* Resolution */
	printf("%f %f %f\n", /* View Point */
		(bound_min_x+bound_max_x)/2.,
		(bound_min_x+bound_max_x)/2.-
		      0.5*fabs(bound_max_x - bound_min_x)/tan(DTOR*27.),
		(bound_min_z+bound_max_z)/2.);
	printf("0 1 0\n");   /* View Plane Normal */
	printf("0 0 1\n");   /* Up Vector */
	printf("53 53\n");   /* Horiozontal field of view and
				vertical field of view. */
	}
}

dump_subdivisions()
{
	double deltax = fabs(bound_max_x - bound_min_x);
	double deltay = fabs(bound_max_y - bound_min_y);
	double deltaz = fabs(bound_max_z - bound_min_z);
	double max = MAX(deltax,MAX(deltay,deltaz));
	printf("%d %d %d\n",(int)(deltax*10./max+0.5),
		(int)(deltay*10./max+0.5),(int)(deltaz*10./max+0.5));
}

write_material_property(mid)
short mid;
{
	int k=0;
	switch (modifier_table.otyp[mid]){
                case ILLUM:
                case GLOW :
		case LIGHT : printf("\t1\n\t\t%f %f %f\n\t0\n\t\t0 0 0\n",
			    	modifier_table.margs[mid].farg[0]/255.,
			    	modifier_table.margs[mid].farg[1]/255.,
			    	modifier_table.margs[mid].farg[2]/255.);
			break;
                case SPOTLIGHT: printf("\t2\n\t\t%f %f %f\n",
			    	modifier_table.margs[mid].farg[0]/255.,
			    	modifier_table.margs[mid].farg[1]/255.,
			    	modifier_table.margs[mid].farg[2]/255.);
			printf ("\t\t%f\n\t\t%f %f %f\n\t0\n\t\t0 0 0\n",
			    	modifier_table.margs[mid].farg[6]/2.,
			    	modifier_table.margs[mid].farg[3],
			    	modifier_table.margs[mid].farg[4],
			    	modifier_table.margs[mid].farg[5]);
			break;
		default : printf("\t0\n");
			switch(modifier_table.otyp[mid]){
				case MIRROR:
				case METAL : printf("\t1\n");
						break;
				default	   : printf("\t0\n");
						break;
			}
			printf("\t\t%f %f %f\n",
			    	modifier_table.margs[mid].farg[0],
			    	modifier_table.margs[mid].farg[1],
			    	modifier_table.margs[mid].farg[2]);
			break;
	}
}

typedef struct {
        	float   x, y;
	}Point2;
typedef struct {
        	float   x, y, z;
	}Point;

static float triangle_area(p1,p2,p3)
Point2 *p1,*p2,*p3;
{
	float a = 0.;
	a = (p2->x-p1->x)*(p2->y+p1->y);
	a += (p3->x-p2->x)*(p3->y+p2->y);
	a += (p1->x-p3->x)*(p1->y+p3->y);
	return(a*0.5);
}
#define SGN(a)          (((a)<0) ? -1 : 0)
#define project(p,P,i) {\
        switch(i){\
                case 0 : /* X axis */\
                        p.x = (P).y; p.y = (P).z; break;\
                case 1 : /* Y axis */\
                        p.x = (P).x; p.y = (P).z; break;\
                case 2 : /* Z axis */\
                        p.x = (P).x; p.y = (P).y; break;\
        }\
}

static int is_convex(n,vlist)
int n;
Point *vlist;
{
	int prevsign;
	int i,j,dominant_axis;
	float maxval;
	Point N;
	Point2 prev,cur,next;
        /* Compute derived data */
                /* Normal by Newels Method */
        N.x = N.y = N.z = 0.;
        for(i=0,j=1;i<n;i++,j++){
                if (j==n)j=0;
                N.x += (vlist[i].y - vlist[j].y)*(vlist[i].z+vlist[j].z);
                N.y += (vlist[i].z - vlist[j].z)*(vlist[i].x+vlist[j].x);
                N.z += (vlist[i].x - vlist[j].x)*(vlist[i].y+vlist[j].y);
        }
	N.x = fabs(N.x); N.y = fabs(N.y); N.z = fabs(N.z);	
	maxval = MAX(N.x,MAX(N.y,N.z));
	dominant_axis = (maxval == N.x)?0:((maxval==N.y)?1:2);

	project(prev,vlist[n-2],dominant_axis);
	project(cur,vlist[n-1],dominant_axis);
	project(next,vlist[0],dominant_axis);
 	prevsign = SGN(triangle_area(&prev,&cur,&next));
	for(i=0;i<n-1;i++){
		prev = cur; cur = next;
		project(next,vlist[i+1],dominant_axis);
		if (SGN(triangle_area(&prev,&cur,&next)) != prevsign)
			 return(0);
	}
	return(1);
}
int read_n_dumppolygon(area,oid,mid,name,fargs)
double area;
short oid,mid;
char *name;
FUNARGS *fargs;
{
	Point *vlist;
        int     i, k=0,nv,convex_quadrilateral_flag;
	int n=sqrt(area/cum_area*max_pieces);

	nv = fargs->nfargs/3;
	
	vlist = (Point *)malloc(sizeof(Point)*nv);
	if (vlist == NULL) 
		error("memory allocation",name);
        for (i = k = 0; i < nv; i++){
        	vlist[i].x=fargs->farg[k++];
		vlist[i].y=fargs->farg[k++];
		vlist[i].z=fargs->farg[k++];
	}
	convex_quadrilateral_flag =  
		((nv == 4) && is_convex(nv,vlist));
	if (n<=0 || !convex_quadrilateral_flag) n = 1;
	printf("%d %d\n",n,n);
	write_material_property(mid);
	printf("\t%d\n",
		(convex_quadrilateral_flag)?oid:oid+8); 
		/* quadrilateral or polygon */
	if (!convex_quadrilateral_flag) printf("\t\t%d\n",nv);
        for (i = 0; i < nv; i++) {
		printf("\t\t%f %f %f\n",vlist[i].x,vlist[i].y,vlist[i].z);
	}
	free(vlist);
}

int read_n_dumpsphere(area,oid,mid,name,fargs)
double area;
short oid,mid;
char *name;
FUNARGS *fargs;
{
	float	x,y,z,r;
	int n=sqrt(area/cum_area*max_pieces);
	if (n<=0) n = 1;
        printf("%d %d\n",n,n);
        write_material_property(mid);
        printf("\t%d\n",oid); /* Geometry */
	x = fargs->farg[0];
	y = fargs->farg[1];
	z = fargs->farg[2];
	r = fargs->farg[3];
	printf("\t\t%f %f %f\n\t\t%f\n",x,y,z,r);
}

int read_n_dumpcylinder(area,oid,mid,name,fargs)
double area;
short oid,mid;
char *name;
FUNARGS *fargs;
{
	float x,y,z,x1,y1,z1,r;
	int n=sqrt(area/cum_area*max_pieces);
	if (n<=0) n = 1;

	printf("%d %d\n",n,n);
	write_material_property(mid);
	printf("\t%d\n",oid); /* Geometry */
	x = fargs->farg[0];
	y = fargs->farg[1];
	z = fargs->farg[2];
	x1 = fargs->farg[3];
	y1 = fargs->farg[4];
	z1 = fargs->farg[5];
	r = fargs->farg[6];
	printf("\t\t%f %f %f\n\t\t%f %f %f\n\t\t%f\n",x,y,z,x1,y1,z1,r);
}

int read_n_dumpcone(area,oid,mid,name,fargs)
double area;
short oid,mid;
char *name;
FUNARGS *fargs;
{
        float x,y,z,r,x1,y1,z1,r1;
	int k=0;
	int n=sqrt(area/cum_area*max_pieces);
	if (n<=0) n = 1;

        printf("%d %d\n",n,n);
        write_material_property(mid);
        printf("\t%d\n",oid); /* Geometry */
	x = fargs->farg[0];
	y = fargs->farg[1];
	z = fargs->farg[2];
	x1 = fargs->farg[3];
	y1 = fargs->farg[4];
	z1 = fargs->farg[5];
	r = fargs->farg[6];
	r1 = fargs->farg[7];
        printf("\t\t%f %f %f\n\t\t%f\n\t\t%f %f %f\n\t\t%f\n",
		x,y,z,r,x1,y1,z1,r1);
}

int read_n_dumpring(area,oid,mid,name,fargs)
double area;
short oid,mid;
char *name;
FUNARGS *fargs;
{
	float x,y,z,nx,ny,nz,R,r;
	int k=0;
	int n=sqrt(area/cum_area*max_pieces);
	if (n<=0) n = 1;

	
	printf("%d %d\n",n,n);
	write_material_property(mid);
	printf("\t%d\n",oid); /* Geometry */
	x = fargs->farg[0];
	y = fargs->farg[1];
	z = fargs->farg[2];
	nx = fargs->farg[3];
	ny = fargs->farg[4];
	nz = fargs->farg[5];
	r = fargs->farg[6];
	R = fargs->farg[7];
        printf("\t\t%f %f %f\n\t\t%f %f %f\n\t\t%f\n\t\t%f\n",
		x,y,z,nx,ny,nz,r,R);
}

int unsupported(area,oid,mid,name,fargs)
double area;
short oid,mid;
char *name;
FUNARGS *fargs;
{
	warn("MC does not support this surface type",name);
}

int (*read_n_dumpobject[MAXPRIMITIVES])()={
        read_n_dumppolygon,
        read_n_dumpsphere,
        read_n_dumpsphere,
        read_n_dumpcylinder,
        read_n_dumpcylinder,
        read_n_dumpcone,
        read_n_dumpcone,
        read_n_dumpring,
	unsupported,
	unsupported
};
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);
}
