/* cc -o rtface1 rtface1.c  rtflib.o rtfglib.o -L /usr/local/sof3/pixar/prman-11.0/lib -lrib -ltarget -lzip -lprmutil -lm
*/
/*								*/
/*	Renderman version of a simple interactive		*/
/*	parameterized face model - F.I.Parke  6 March 2002
				  Updated     23 May 2002
	Based on GL version		      10 May 90		*/
/*								*/
/*	Simple keyboard driven version				*/
/*								*/
/*	Uses files:	rt1.pts		first vertex points	*/
/*			rt2.pts		second vertex points	*/
/*			rtt.top		topology data		*/
/*								*/
/*	Link with:	-lrib -ltarget -lzip lprmutil -lm	*/
/*								*/
#include "stdio.h"
#include "/usr/local/sof3/pixar/prman-11.0/include/ri.h"
#include "device.h"
#include "math.h"

RtInt frame = 0;
int pmnum;

/*	routine which uses the ring procedure to	*/
/*	create the eyeball polygons			*/
/*							*/
/*	input parameters control the size of the	*/
/*	eyeball, iris, and pupil			*/

void bands(spp,lpp,sn,ln,c,sf,gp)
float spp[16][3],lpp[16][3],sn[16][3],ln[16][3],c[2][3],sf[3],gp;
	{
	 int i,j,k,n;
	 float rad,ct,sg,v[3];
	 float lp[16][3],sp[16][3];
	 RtPoint Band [4];
	 RtPoint NBand [4];
	 for (k=0; k<=1; k+=1)
		{
		  for (i=0; i<=15; i+=1)
		  {
		  for (j=0; j<=2; j+=1)
			v[j]=(spp[i][j]+c[k][j])*sf[j];
		  rad=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
		  if (rad==0.0)
			{ct=0.0;}
		  else
			{ct=v[2]/rad;};
		  sg=1.0/(1.0-gp*(1.0-ct));
		  for (j=0; j<=2; j+=1)
			sp[i][j]=sg*v[j];
		  };
		  for (i=0; i<=15; i+=1)
		  {
		  for (j=0; j<=2; j+=1)
			v[j]=(lpp[i][j]+c[k][j])*sf[j];
		  rad=sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
		  if (rad==0.0)
			{ct=0.0;}
		  else
			{ct=v[2]/rad;};
		  sg=1.0/(1.0-gp*(1.0-ct));
		  for (j=0; j<=2; j+=1)
			lp[i][j]=sg*v[j];
		  };
		  for (i=0; i<=15; i+=1)
			{
			if (i<15) {j=i+1;} else {j=0;};
			for(n=0; n<3; n++)
			  {
			   Band[0][n]  = sp[i][n];
			   NBand[0][n] = sn[i][n];
			   Band[1][n]  = lp[i][n];
			   NBand[1][n] = ln[i][n];
			   Band[2][n]  = lp[j][n];
			   NBand[2][n] = ln[j][n];
			   Band[3][n]  = sp[j][n];
			   NBand[3][n] = sn[j][n];
			  };
			RiPolygon((RtInt) 4, RI_P, (RtPointer) Band,
					     RI_N, (RtPointer) NBand, RI_NULL);
			
			};
		};
	}

/*	routine which displays a new face image		*/

void show (ng,np,ry,rz,sc,pt,pc,pg,pgni,nn,vn,pgn,pm,coord)
int ng,np;
int ry,rz; float sc;
float pt[300][3];
int pc[300], pg[300][4];
int pgni[400][4], nn[400];
float vn[400][3];
float pgn[300][3];
float pm[51], coord[2][3];
	{
	  int f,i, j, k, l, m, n, v;

	  float rp1[16][3],rp2[16][3],rn1[16][3],rn2[16][3];
	  float con[3], pot[3];
	  float er, fi, ff, pf, s, wh,gp;
	  float sf[3];
	  RtPoint cn[4], rcn[4];
	  RtPoint  cp[4], rcp[4];
	  RtColor fcolors[8] = {1.0, .72, .59,	/*flesh*/
	  			0.0, 0.0, 0.0,	/*black*/
          			.95, .95, 1.0,	/*white*/
	  			.2,.2,0,	/*iris*/
	  			.07, .07, 0,	/*fringe*/
				1.0, .2, .3,	/*lips*/
				.2, .2, 0.0,	/*brows*/
				.85, .85, .85};	/*teeth*/
	  RtFloat kd = .8;
	  RtFloat ka = .2;
	  RtFloat ks = .8;
	  RtFloat fov = 30;
	  gp=pm[46];
	  er = pm[44];
	  fi = pm[43];
	  ff = pm[42];
	  pf = pm[41];
	  s  = pm[50];
	  pf = pf*fi;
	  ff = ff*fi;
	  wh = (1.+fi)/2.;
	  sf[0]=pm[7]; sf[1]=pm[8]; sf[2]=pm[9];

/*	Initialize Frame		*/

	/* RiBegin(RI_NULL); */

	RiFrameBegin(frame);

	RiProjection("perspective", RI_FOV, (RtPointer)&fov, RI_NULL);
	RiTranslate(0, 10, 200);
	RiRotate(90, 0, 1, 0);
	RiRotate(-90, 1, 0, 0);
	RiScale(.1, .1, .1);

	RiDisplay("window", RI_FRAMEBUFFER, RI_RGBA, RI_NULL);
	RiFormat((RtInt) 512, (RtInt) 512, 1.0);
	
	RiLightSource("ambientlight", RI_NULL);

	RiTransformBegin();
	RiRotate(60, 0, 1, 0); 
	RiLightSource("distantlight",RI_NULL);

	RiTransformEnd();

	RiWorldBegin(); 
	RiColor(fcolors[0]);

	RiSurface("plastic", "Ka", (RtPointer)&ka, "Kd", (RtPointer)&kd, RI_NULL);

/*	render the face mask polygons		*/

	   for (i=1; i<=ng; i+=1) 
		{
		 if (pg[i][3]==0)
			{ k=2;} else { k=3;}
		 for(j=0; j<=k; j+=1)
			{ m=pg[i][j];
			  v=m;
			  if(pgni[i][j]>1)
				for (l=1; l<=(pgni[i][j]-1); l+=1) v=nn[v];
			  for (n=0; n<3; n+=1)
				{ cn[j][n]=s*vn[v][n]+(1.0-s)*pgn[i][n];
				  cp[j][n]=pt[m][n];};
			};
		 RiPolygon((RtInt) k+1, RI_P, (RtPointer) cp,
					       RI_N, (RtPointer) cn, RI_NULL);
		
		 for(j=k;j>=0;j-=1)
			{ m=k-j;
			  rcn[j][0]=  cn[m][0]; 
			  rcn[j][1]=(-cn[m][1]);
			  rcn[j][2]=  cn[m][2];
			  rcp[j][0]=  cp[m][0]; 
		          rcp[j][1]=(-cp[m][1]);
			  rcp[j][2]=  cp[m][2];
			};
		 RiPolygon((RtInt) k+1, RI_P, (RtPointer) rcp,
					       RI_N, (RtPointer) rcn, RI_NULL);	
		}; 

	/*	display the eyes	*/

	/*	output pupil		*/

	  ring(er,0.0,rp2,rn2);
	  ring(er,pf,rp1,rn1);
	  RiSurface("plastic",RI_NULL); 
	  RiColor(fcolors[1]);
	  bands(rp2,rp1,rn2,rn1,coord,sf,gp); 

	/*	output iris			*/

	  ring(er,ff,rp2,rn2);
	  RiColor(fcolors[3]);
	  bands(rp1,rp2,rn1,rn2,coord,sf,gp); 

	/*	output fringe			*/

	  ring(er,fi,rp1,rn1);
	  RiColor(fcolors[4]);
	  bands(rp2,rp1,rn2,rn1,coord,sf,gp); 

	/*	output first white		*/

	  ring(er,wh,rp2,rn2);
	  RiColor(fcolors[2]);
	  bands(rp1,rp2,rn1,rn2,coord,sf,gp); 

	/*	output second white		*/

	  ring(er,1.0,rp1,rn1);
	  bands(rp2,rp1,rn2,rn1,coord,sf,gp); 

	RiWorldEnd();
	RiFrameEnd();

	frame++;
	}


void main(void)
	{
	  short val;
	  char c, name[20], line[80];
	  int index, frame; float misc;
	  FILE *fp, *fopen();
	  int i, j, k, n, io, np, ng, npts, nnor, nv, done;
	  int ry, rz, cindex; float sc,x,y,cvalue,xvalue,yvalue;
	  float pm[51];
	  float coord[3], crd[2][3], eyeball[2][3];
	  float pt[300][3], inpts[300][3], interp[300][3];
	  float pgn[300][3];
	  int nn[400];
	  float vn[400][3];
	  int pc[300],pg[300][4];
	  int pgni[400][4];

	/* initialization				*/

	  done = 0;
	  coord[0]=190; coord[1]=125; coord[2]=0;
	  npts=300; nnor=400;

	/*	initialize parameter values	*/

	  pm[1] = .9;	/* eye opening (0.0<=>1.0)		*/
	  pm[2] = .5;	/* eyebrow arch (0.0<=>1.0)		*/
	  pm[3] = .0;	/* eyebrow separation (0.0<=>25.0)	*/
	  pm[4] = .0;	/* jaw rotation (0.0<=>20.0)		*/
	  pm[5] = 1.0;	/* eyelid Y scale			*/
	  pm[6] = 1.0;	/* eyelid Z scale			*/
	  pm[7] = 1.0;	/* head X scale				*/
	  pm[8] = 1.0;	/* head Y scale				*/
	  pm[9] = 1.0;	/* head Z scale				*/
	  pm[10]= 1.0;	/* nose tip Y scale			*/
	  pm[11]= 1.0;	/* nose bridge Y scale			*/
	  pm[12]= 1.0;	/* mouth Y scale			*/
	  pm[13]= 1.0;	/* mouth interpolation (0.0<=>1.0)	*/
	  pm[14]=  .0;	/* mouth X offset			*/
	  pm[15]=  .0;	/* 287 Y offset				*/
	  pm[16]=  .0;	/* mouth corner X offset		*/
	  pm[17]=  .0;	/* mouth corner Y offset		*/
	  pm[18]=  .0; 	/* mouth corner Z offset		*/
	  pm[19]= 1.0;	/* jaw Y scale				*/
	  pm[20]= 1.0;	/* cheek Y scale			*/
	  pm[21]=  .0;	/* lower lip 'f' tuck			*/
	  pm[22]=  15.0;/* raise upper lip			*/
	  pm[26]=  .0;	/* nose tip X offset			*/
	  pm[27]=  .0;	/* nose tip Z offset			*/
	  pm[28]=  .0;  /* eyeball X offset			*/
	  pm[29]=  .0;  /* eyeball Y offset			*/
	  pm[30]=(-15.0);  /* eyeball Z offset			*/
	  pm[31]=  .0;	/* chin X offset			*/
	  pm[32]=  .0;	/* chin Z offset			*/
	  pm[35]= 1.0;	/* chin to mouth scaling		*/
	  pm[36]= 1.0;	/* chin to eye scaling			*/
	  pm[37]= 1.0;	/* eye to forehead scaling		*/
	  pm[38]=  .0;	/* eyelid X offset			*/
	  pm[39]=  .0;	/* eyelid Y offset			*/
	  pm[40]=  .0;  /* eyelid Z offset			*/
	  pm[41]=  .4;	/* pupil fraction			*/
	  pm[42]= .85;	/* fringe fraction			*/
	  pm[43]=  .4;  /* iris fraction			*/
	  pm[44]= 70.;	/* eyeball radius			*/
	  pm[45]= 80.;	/* eyelid radius			*/
	  pm[46]= 0.0;  /* growth factor			*/
	  pm[47]= 0.0;	/* teeth x offset			*/
	  pm[48]=38.0;	/* teeth z offset			*/
	  pm[50]= 1.0;	/* smoothness (1.0=smooth,0.0=faceted)	*/

	/*	read in data files				*/

	  np=readpt(inpts, "rt1.pts");	/* read first vertices set	*/

	  for (i=0; i<300; i++)
	  for (j=0; j<3; j++) interp[i][j] = inpts[i][j];

	  np=readpt(interp, "rt2.pts");	/* read second vertices set	*/
	  ng=readt(pc,pg,pgni);	/* read topology file	*/

	/*	Initialize Renderman		*/

	RiBegin(RI_NULL); 

	pmnum=4; nv=0; ry=(100); rz=(-900); sc=.002; 

	/*	initialize eyeball positions	*/

	for(i=0; i<2; i+=1)
	for(j=0; j<3; j+=1)
	     { crd[i][j]=coord[j]+pm[j+38];
	       eyeball[i][j]=crd[i][j]+pm[j+28];};
	crd[0][1]=(-crd[0][1]);
	eyeball[0][1]=(-eyeball[0][1]);

	/*	initialize vertex positions	*/

	points(np,crd,pm,inpts,interp,pt);

	/*	compute polygon normals		*/

	comnor(ng,pg,pt,pgn);

	/*	compute vertex normals		*/

	vnorm(nnor,ng,np,nv,nn,pg,pgni,pgn,vn,pt);

	/*	display initial face image	*/

	show(ng,np,ry,rz,sc,pt,pc,pg,pgni,nn,vn,pgn,pm,eyeball);

	/*	MAIN CONTROL LOOP				*/

	while(done == 0)
		 { fprintf(stderr,"\n>");
		   fgets(line,80,stdin);
		   sscanf(line,"%c",&c);

		   if (c=='p')	/*	change parameter value	*/
			{
			  fprintf(stderr,"parameter number = ");
			  fgets(line,80,stdin);
			  sscanf(line,"%d",&n);
			  fprintf(stderr,"parameter value = ");
			  fgets(line,80,stdin);
			  sscanf(line,"%f",&pm[n]);
			} else

		  if (c=='r')	/*	read parameter value	*/
			{
			  fprintf(stderr,"parameter number = ");
			  fgets(line,80,stdin);
			  sscanf(line,"%d",&n);
			  fprintf(stderr,"parameter value = %f\n",pm[n]);
			} else

		   if (c=='d')	/*	display new face	*/
			{
			  for(i=0; i<2; i+=1)
			  for(j=0; j<3; j+=1)
			      { crd[i][j] = coord[j]+pm[j+38];
				eyeball[i][j]=crd[i][j]+pm[j+28];};
			  crd[0][1]=(-crd[0][1]);
			  eyeball[0][1]=(-eyeball[0][1]);

		          points(np,crd,pm,inpts,interp,pt);
		          comnor(ng,pg,pt,pgn);
		          vnorm(nnor,ng,np,nv,nn,pg,pgni,pgn,vn,pt);
		          show(ng,np,ry,rz,sc,pt,pc,pg,pgni,nn,vn,pgn,pm,eyeball);
			} else

		   if (c=='q')	/*	termination		*/
			{
			  done=1;
			  fprintf(stderr,"terminated\n");
			} else 
                  fprintf(stderr,"command error, try again\n>");
                };
	  RiEnd();
        }
