/* ==========================================================================
                            DISPLAY_C
=============================================================================

    DESCRIPTION
    This module is responsible for displaying (rendering) the face geometry. It
	as has routines for calculating the polygon normals.

    HISTORY
	1/01   steve dipaola    ported from SGI via GLUT example files


    FUNCTION NAMES
    paint_polygons			-- display the polygons.
	comnor()				-- calculate common (poly) normals
	vnorm( float smooth )   -- calculate vector (point) normals


    C SPECIFICATIONS
    paint_polygons ()
	comnor()
	vnorm( float smooth )

============================================================================ */

#include <math.h>           /* C header for any math functions               */
#include <stdio.h>          /* C header for standard I/O                     */
#include <string.h>         /* For String compare                            */
#include <stdlib.h>
#ifndef _WIN32
#include <sys/types.h>
#include <sys/file.h>
#endif
#include <GL/glut.h>        /* OpenGl headers   - aadesche       */

#include "head.h"	   /* local header for the face		             */

//yw changed! start
extern int texture;
extern int useTexturing;
extern float face_specular;
extern float face_brightness;
GLfloat white[] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat black[] = {0.0f, 0.0f, 0.0f, 1.0f};
GLfloat gray1[] = {0.1f, 0.1f, 0.1f, 1.0f};
GLfloat gray2[] = {0.2f, 0.2f, 0.2f, 1.0f};
GLfloat gray3[] = {0.3f, 0.3f, 0.3f, 1.0f};
GLfloat gray5[] = {0.5f, 0.5f, 0.5f, 1.0f};
GLfloat gray7[] = {0.7f, 0.7f, 0.7f, 1.0f};
//yw changed! end


/* ========================================================================= */
/* paint_polygons                                                            */
/* ========================================================================= */
/*
** Paints the polygons of the face.
** Type indicates if they are to be
** drawn         (type=0),
** flat shaded   (type=1),
** smooth shaded (type=2).
*/

void paint_polygons_sub ( int type, int mode)
{
  int    i, j ;
  float  v1[3], v2[3], v3[3] ;
  float  norm1[3], norm2[3], norm3[3] ;
  GLfloat dM[4]= { 0.0,0.5,0.0,1.0 };
  GLfloat sM[4]= { 0.5,0.5,0.5,1.0 };
  GLfloat ts[4]= { face_specular, face_specular, face_specular, face_specular};
  GLfloat tb[4]= { face_brightness, face_brightness, face_brightness, face_brightness};
  GLfloat shininessM[1] = {6.0};
  //yw changed! start
  int textureIt;
  int a=2, b=1, c=0;
  //yw changed! end

  glLineWidth   ( 2.0 ) ;

  for (i=0; i<g_np; i++ )  /* for all polygons */
    {
	    sM[0]=0.4;sM[1]=0.4;sM[2]=0.4;sM[3]=1.0;
		shininessM[0] = 6.0;
	  //yw changed! start
      textureIt = 1;
	  //yw changed! end
      /* if cmap data change, define different diffuse material */
	  if (g_pc[i] != g_pc[i-1] ) {
		  if      (g_pc[i] == 1 ) { dM[0]=0.73; dM[1]=0.36; dM[2]=0.32; } /* 1 skin = flesh */
		  else if (g_pc[i] == 2 )
			  if (g_facetype==HUMAN) {
					dM[0]=0.2; dM[1]=0.1; dM[2]=0.12;
					sM[0]=1.0; sM[1]=1.0; sM[2]=1.0;sM[3]=1.0;
					shininessM[0] = 5.0;
			  }    /* 2 hair = brown */
			  else { dM[0]=0.73; dM[1]=0.36; dM[2]=0.32; }    /* 2 bald hair = flesh */
		  else if (g_pc[i] == 3 ) { dM[0]=0.0; dM[1]=0.0; dM[2]=0.0; }   /* 3 brows */
		  else if (g_pc[i] == 4 ) { dM[0]=0.0; dM[1]=0.0; dM[2]=0.0; }   /* 4 top lash */
		  else if (g_pc[i] == 5 ) { dM[0]=0.0; dM[1]=0.0; dM[2]=0.0; }   /* 5 bot lash */
		  else if (g_pc[i] == 6 ) { dM[0]=0.0; dM[1]=0.0; dM[2]=0.0; }	 /* 6 nostril */
		  else if (g_pc[i] == 7 ) {
			dM[0]=0.99; dM[1]=0.28; dM[2]=0.28;
			sM[0]=1.0; sM[1]=1.0; sM[2]=1.0;sM[3]=1.0;
			shininessM[0] = 126.0;
			}   /* 7 lips = red */
		  else if (g_pc[i] == 8 ) { dM[0]=1.0; dM[1]=1.0; dM[2]=1.0; }
		  else if (g_pc[i] == 9 ) { dM[0]=0.0; dM[1]=0.0; dM[2]=0.0; }
		  else if (g_pc[i] == 10 ) { dM[0]=0.9; dM[1]=0.9; dM[2]=0.9;}		/* 8 eye white = white*/
		  else if (g_pc[i] == 11 ) {
				dM[0]=0.2; dM[1]=0.2; dM[2]=0.2;
				sM[0]=1.0; sM[1]=1.0; sM[2]=1.0; sM[3]=1.0;
				shininessM[0] = 127.0;
		  }	    /* 9 pupil = black */
	  }

   /* gl color commands */
	  //yw changed! start
	   	 //if (g_pc[i] == 10 || g_pc[i] == 11 || !useTexturing)
 	 if (!useTexturing)
	  {
		glMaterialfv  ( GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,dM);

		textureIt = 0;
	  }
		// try by CYJ

	 //yw changed! end
	// victor add mode=1:nomal, mode=2:white, mode=3: specular only
		if (mode==2){
		  		glMaterialfv  ( GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,white);
				glMaterialfv  ( GL_FRONT_AND_BACK,GL_SPECULAR,black);
				glMaterialfv(GL_FRONT, GL_DIFFUSE, tb);
				glMaterialfv(GL_FRONT, GL_SPECULAR, black);
				glBlendFunc(GL_ZERO, GL_SRC_COLOR);
		}else if (mode==3){

					glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE, gray1);
					glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, ts);
					if (g_pc[i] == 7 ) {
						glMaterialf(GL_FRONT_AND_BACK ,GL_SHININESS,6.0f);
					}else if (g_pc[i] == 11 ){
						glMaterialf(GL_FRONT_AND_BACK ,GL_SHININESS, 6.0f);
					}else if (g_pc[i] == 2 ) {
						glMaterialf(GL_FRONT_AND_BACK ,GL_SHININESS, 6.0f);
					}else{
						glMaterialf(GL_FRONT_AND_BACK ,GL_SHININESS, 6.0f);
					}
					glBlendFunc(GL_ONE, GL_ONE);
		}else{
	  		glMaterialfv  ( GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,dM);
	  //CYJ//
			glMaterialfv  ( GL_FRONT_AND_BACK,GL_SPECULAR,sM);
			glMaterialfv( GL_FRONT_AND_BACK ,GL_SHININESS,shininessM);

		}
    //end of
   for (j=0; j<3; j++) { /* get points */
	v1[j] = g_pt[g_pg[i][2]][j] ;
	v2[j] = g_pt[g_pg[i][1]][j] ;
	v3[j] = g_pt[g_pg[i][0]][j] ;
      }

      if ( type == 0 ) {

	for (j=0; j<3; j++) { /* get normals */
	  norm1[j] = g_vn[g_pg[i][2]][j] ;
	  norm2[j] = g_vn[g_pg[i][1]][j] ;
	  norm3[j] = g_vn[g_pg[i][0]][j] ;
	}
	glBegin ( GL_LINE_LOOP ) ; {
	  glNormal3f ( norm1[0], norm1[1], norm1[2] ) ;
	  glVertex3f ( v1[0],    v1[1],    v1[2]    ) ;
	  glNormal3f ( norm2[0], norm2[1], norm2[2] ) ;
	  glVertex3f ( v2[0],    v2[1],    v2[2]    ) ;
	  glNormal3f ( norm3[0], norm3[1], norm3[2] ) ;
	  glVertex3f ( v3[0],    v3[1],    v3[2]    ) ;
	}  glEnd ( ) ;

      } /* end if drawn */

      if ( type == 1 ) {

	for (j=0; j<3; j++) {
	  norm1[j] = g_pgn[i][j] ;
	  norm2[j] = g_pgn[i][j] ;
	  norm3[j] = g_pgn[i][j] ;
	}
	glBegin ( GL_TRIANGLES ) ; {
	  glNormal3f ( norm1[0], norm1[1], norm1[2] ) ;
	  glVertex3f ( v1[0],    v1[1],    v1[2]    ) ;
	  glNormal3f ( norm2[0], norm2[1], norm2[2] ) ;
	  glVertex3f ( v2[0],    v2[1],    v2[2]    ) ;
	  glNormal3f ( norm3[0], norm3[1], norm3[2] ) ;
	  glVertex3f ( v3[0],    v3[1],    v3[2]    ) ;
	}  glEnd ( ) ;


      } /* end if flat */

      else if ( type == 2 ) {

	for (j=0; j<3; j++) {
	  norm1[j] = g_vn[g_pg[i][2]][j] ;
	  norm2[j] = g_vn[g_pg[i][1]][j] ;
	  norm3[j] = g_vn[g_pg[i][0]][j] ;
	}
    /* glColor4fv(diffuseMaterial); */
	//yar added this shit!!

	//yw changed! start
/*  by cyj - moved to the mainpart

	if (useTexturing)
	{
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, texture);
	}
	else
	{
		glColor3d(1,1,1);
	}

	*/
	// by cyj
	glBegin ( GL_TRIANGLES ) ; {
	  if (textureIt)
		glTexCoord3f(tex[i][a][0], tex[i][a][1], tex[i][a][2]);
//	  glTexCoord2f(tex[i][0][0], tex[i][0][1]);
	  glNormal3f ( norm1[0], norm1[1], norm1[2] ) ;
	  glVertex3f ( v1[0],    v1[1],    v1[2]    ) ;
	  if (textureIt)
		glTexCoord3f(tex[i][b][0], tex[i][b][1], tex[i][b][2]);
//	  glTexCoord2f(tex[i][1][0], tex[i][1][1]);
	  glNormal3f ( norm2[0], norm2[1], norm2[2] ) ;
	  glVertex3f ( v2[0],    v2[1],    v2[2]    ) ;
	  if (textureIt)
		glTexCoord3f(tex[i][c][0], tex[i][c][1], tex[i][c][2]);
//	  glTexCoord2f(tex[i][2][0], tex[i][2][1]);
	  glNormal3f ( norm3[0], norm3[1], norm3[2] ) ;
	  glVertex3f ( v3[0],    v3[1],    v3[2]    ) ;
	}  glEnd ( ) ;
/* by cyj
	glDisable(GL_TEXTURE_2D);
	*/
      } /* endif painted */

	//yw changed! end
    }
  glLineWidth   ( 1.0 ) ;
}

// victor chen
void paint_polygons ( int paint_type){
	GLboolean lighting = GL_TRUE;		/* Enable lighting passes */
	//GLboolean lighting = GL_FALSE;
	GLboolean specular = GL_TRUE;		/* Enable specular lighting */
	GLboolean drifting = GL_FALSE;		/* Enable texture movement */
	GLboolean linear = GL_FALSE;		/* Enable linear filtering */
	GLboolean useDepth = GL_FALSE;		/* Enable depth buffering */
	GLuint octaves = 1;			/* How many octaves of noise */


	GLuint pass;
	GLfloat amplitude;
	int type;
	type = paint_type;
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	if (useTexturing)
	{

		/*
		* PASS     Blending   Lighting Shade    DepthFunc  DepthMask
		*
		* tex 0	   No	     No     FLAT      LEQUAL       True
		* tex 1      Yes[1]     No     FLAT      EQUAL        False
		* tex n      Yes[1]     No     FLAT      EQUAL        False
		* diffuse    Yes[2]     Yes    SMOOTH    EQUAL        False
		* specular   Yes[1]     Yes    SMOOTH    EQUAL        False
		*
		* Notes:
		*   [1]   glBlendFunc(GL_ONE, GL_ONE)
		*   [2]   glBlendFunc(GL_ZERO, GL_SRC_COLOR)
		*/

		if (useDepth) {
			//glEnable(GL_DEPTH_TEST);
		} else {
			//glDisable(GL_DEPTH_TEST);
		}

		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		glDisable(GL_LIGHTING);
		glDisable(GL_DITHER);
		//glShadeModel(GL_FLAT);
		glShadeModel(GL_SMOOTH);

		if (useDepth) {
			glDepthFunc(GL_LEQUAL);
			glDepthMask(GL_TRUE);
		}

		if (octaves == 0) {
			/* No texture, just draw a solid white cube */

			glDisable(GL_BLEND);
			glDisable(GL_TEXTURE_2D);

			glColor3f(1.0f, 1.0f, 1.0f);
			paint_polygons_sub (type,1);
		} else {
			/* Build up the texture in several passes.  See
			* "Texturing and Modeling - A Procedural Approach"
			* (ISBN 0-12-228760-6) page 86.
			*/


			amplitude = 0.5F;

			for (pass = 0; pass < octaves; pass++) {
				if (pass == 0) {
					glDisable(GL_BLEND);
					glEnable(GL_TEXTURE_2D);
					glBindTexture(GL_TEXTURE_2D, texture);
					paint_polygons_sub (type,2);
				} else {
					glEnable(GL_BLEND);
					//glDisable(GL_BLEND);
					glBlendFunc(GL_ONE, GL_ONE);
					if (useDepth) {
						glDepthFunc(GL_EQUAL);
						glDepthMask(GL_FALSE);
					}
					glColor3f(1.0, 1.0, 1.0);
					//glColor3f(amplitude, amplitude, amplitude);
					paint_polygons_sub (type,2);
				}




				/* Changing these two factors can have interesting effects... */
				amplitude *= 0.5f;  /* .. increasing this gives a grainier feel. */
			}
		}

			/* Now light the cube.  */
			if (lighting) {
				glEnable(GL_LIGHTING);
				glDisable(GL_TEXTURE_2D);
				//glEnable(GL_TEXTURE_2D);
				glEnable(GL_BLEND);
				//glDisable(GL_BLEND);
				glShadeModel(GL_SMOOTH);

				if (useDepth) {
					glDepthFunc(GL_EQUAL);
					glDepthMask(GL_FALSE);
				}

				/* First, diffuse illumination.  The blend func is
				* (GL_ZERO, GL_SRC_COLOR) because we want to modulate
				* the texture by the lighting color.
				* This pass only needs the diffuse component
				* of any lighting calculation, hence the material
				* setup.
				*/

				/* If this is the final pass, we should dither */
				if (!specular)
					glEnable(GL_DITHER);

				paint_polygons_sub (type,2);

				/* Second, specular component, which is additive,
				* so use blend func (GL_ONE, GL_ONE).
				* Note that the material this time is set up
				* to give _just_ the specular component of lighting.
				*/
				if (specular) {
					glEnable(GL_DITHER);
					/* This must be the final pass, so enable dither */


					paint_polygons_sub (type,3);
				}
		}
		//glDisable(GL_BLEND);
		//glEnable(GL_TEXTURE_2D);
		//glBindTexture(GL_TEXTURE_2D, texture);
		//paint_polygons_sub (type);

	}
	else
	{
		glDisable(GL_BLEND);

		glDisable(GL_TEXTURE_2D);
		glColor3d(1,1,1);
		paint_polygons_sub (type,1);
	}


}
// end_victor chen



/*			*** comnor ***			*/
/*  - calculate (normalized) common (polygon) normals   */
void
comnor()
{
   float lx;
   int i, j;
   float x[3], p0[3], p1[3], p2[3];

   for ( i=1; i<=g_ng; i++) {
      for ( j=0; j<3; j++) {
         p0[j]=g_pt[g_pg[i][0]][j];
         p1[j]=g_pt[g_pg[i][1]][j]-p0[j];
         p2[j]=g_pt[g_pg[i][2]][j]-p0[j];

      }
      x[0]=p1[1]*p2[2]-p1[2]*p2[1];
      x[1]=p1[2]*p2[0]-p1[0]*p2[2];
      x[2]=p1[0]*p2[1]-p1[1]*p2[0];

      lx=sqrt(x[0]*x[0]+x[1]*x[1]+x[2]*x[2]);
      if (lx==0.0) {
      lx=1.;

      }
      for ( j=0; j<3; j++ )
         g_pgn[i][j]=x[j]/lx;
   }
}

/*			*** vnorm ***			*/
/*	- calculate vertex (normalized) normals		*/
void
vnorm( float smooth )

{
   int i, j, k, l, nv, vertex;
   float length;
   float vpn[3];

   for (i=0; i<=MAX_PT_POLY; i++)
      for (j=0; j<3; j++) {   /* init vert norms, crease offsets */
         g_vn[i][j]=0.0;
         g_nn[i]=0;
      }
   nv=g_np;

   for (i=1; i<=g_ng; i++)    /* for all plys */
      for (j=0; j<3; j++)     /* all points */
         if (g_pg[i][j]>0) {               /* must be real point */
            vertex=g_pg[i][j];
            if (g_pgni[i][j]>1)			/* crease ? */
               for (l=1; l<=(g_pgni[i][j]-1); l++)
                  if (g_nn[vertex]==0) {
                     nv=nv+1;
                     g_nn[vertex]=nv;
                     vertex=nv;
                  }
                  else vertex=g_nn[vertex];

            for ( k=0; k<3; k++)      /* add up norms of all polys vertex has */
               g_vn[vertex][k]+=g_pgn[i][k];
         }

  if (smooth) {  /* smooth out normals - currently don't use */
   for (i=1; i<=1082; i++) {   /* for all plys except ears*/
      for (l=0; l<3; l++) /* add up all vertex morms for poly */
	  vpn[l] = (g_vn[ g_pg[i][0] ][l]+g_vn[ g_pg[i][1] ][l]+g_vn[ g_pg[i][2] ][l])/3.0;
      for (j=0; j<3; j++)     /* all points */
         for ( k=0; k<3; k++)   /* add up part of vnorms of other pts on poly */
               g_vn[ g_pg[i][j] ][k] += smooth*vpn[k];
  }
}

   for (i=1; i<=nv; i++) {   /* unitize normal */
      length=sqrt(g_vn[i][0]*g_vn[i][0]+g_vn[i][1]*g_vn[i][1]+g_vn[i][2]*g_vn[i][2]);
      for (j=0; j<3; j++)
         if (length) g_vn[i][j]=g_vn[i][j]/length;
         else g_vn[i][j]=0.0;
   }
 /* copy vert normals on sym points
   for (i=0; i<SYMMAX; i++)
      for (j=0; j<3; j++)
         g_vn[sym[i]+300][j]=g_vn[g_sym[i]][j];
  */
}
