// intro for seasons.
// $Header: /Users/jch/zStuff/cvsstuff/cvsroot/trivo/yinyang.c,v 1.23 2005/12/23 20:12:26 jch Exp $
// Copyright 2003 YON - Jan C. Hardenbergh. Permission to copy is
// granted as long as this copyright and this URL are maintained:
// http://www.jch.com/NURBS/
//
// gcc yinyang.c  -lglut -lGLU -lGL -lm
#include <GL/glut.h>
#include <stdlib.h>
#include <image.h>

extern int LoadJPEGTexture(const char *filename, int *outWidth, int *outHeight);

#define PIE 3.141593
// toZoom was 28, now it will be 42
// unroll was 173, now... 256
#define TOZOOM 30
#define UNROLL 214
#define kOuterRadius 0.9
#define kDeltaPeriod 12

static int gFrame = 0;
static int gLastFrame = 260;
static int gSaveAnim = 0;
static int gVerbose = 0;
static int gHaveImage = 0;
static double dAngle = 0.1;
static double gFlipY = 1;
static double gAngle = -180;
static double gDeltaAngle = kDeltaPeriod;
static int gStart3 = 0;

int getArcVertices(double center[2], double angles[2], double radii[2], int maxVertex, GLfloat vertices[][2])
{
  double angle;
  double radius;
  double dRadius;
  int steps, i;
  double startAngle;
  double endAngle;
  double deltaAngle;

  startAngle = angles[0];
  endAngle = angles[1];

  // while (startAngle > 2*PIE) startAngle -= 2*PIE;
  // while (startAngle > 2*PIE) startAngle -= 2*PIE;
  while (endAngle < startAngle) endAngle += 2*PIE;

  steps = (int)(fabs(endAngle - startAngle)/dAngle);
  if (steps >= maxVertex)
    return -1;

  deltaAngle = (endAngle - startAngle)/(double)(steps);
  dRadius = (radii[1] - radii[0])/(double)(steps);

  radius = radii[0];
  angle = startAngle;
	
  for(i = 0; i <= steps; i++)
    {
      vertices[i][0] = (GLfloat)(center[0] + radius*cos(angle));
      vertices[i][1] = (GLfloat)(center[1] + radius*sin(angle));
      radius += dRadius;
      angle += deltaAngle;
    }
  return steps;
}

#define MAX_VERTS 200
void drawArc(double center[2], double angles[2], double radii[2])
{
  GLfloat vertices[MAX_VERTS][2];
  int steps, i;

  steps = getArcVertices(center, angles, radii, MAX_VERTS, vertices);

  glBegin(GL_LINE_STRIP);
	
  for(i = 0; i <= steps; i++)
    {
      glVertex2fv(vertices[i]);
    }
  glEnd();
}
/*

void getCorners(float point1[2], float point2[2], float scale, float corners[2][2])
{
  double dx = point2[0] - point1[0];
  double dy = point2[1] - point1[1];
  double length = sqrt(dx*dx + dy*dy);
  // scale, normalize and rotate by 90.
  float sdy = scale * 0.5 * (float)dx/length;
  float sdx = - scale * 0.5 * (float)dy/length;
  
  corners[0][0] = point1[0] + sdx;
  corners[0][1] = point1[1] + sdy;
  corners[1][0] = point1[0] - sdx;
  corners[1][1] = point1[1] - sdy;

  //printf("getCorners in %g %g, %g, %g, out %g, %g, %g, %g, sdx,y %g, %g, length %g\n", 
  //	 point1[0],point1[1],point2[0],point2[1], 
  //	 corners[0][0], corners[0][1],corners[1][0], corners[1][1], sdx, sdy, length );
}

int calcWideLines(int n, float centerLine[][2], float scale, float deltaScale, float wideLine[][2])
{
  if (n<2)
    return -1;
  /*
  printf("widelines n = %d, scale = %g, ds = %g", n, scale, deltaScale);
  for (int prin = 0; prin < n; prin++) printf(" (%g, %g),", centerLine[prin][0], centerLine[prin][1]);
  printf("\nok\n");
  *
  getCorners(centerLine[0], centerLine[1], scale, &wideLine[0]);
  if (n*deltaScale > scale)
    deltaScale = scale/(n*1.4);
  float nextScale = scale - deltaScale;
  int index = 2;
  while (index < n)
    {
      // calculate points.
      double vec1x = centerLine[index-1][0] - centerLine[index-2][0];
      double vec1y = centerLine[index-1][1] - centerLine[index-2][1];
      double vec2x = centerLine[index-1][0] - centerLine[index][0];
      double vec2y = centerLine[index-1][1] - centerLine[index][1];

      double length = sqrt(vec1x*vec1x + vec1y*vec1y);
      vec1x /= length;
      vec1y /= length;

      length = sqrt(vec2x*vec2x + vec2y*vec2y);
      vec2x /= length;
      vec2y /= length;

      double dot = vec1x*vec2x + vec1y*vec2y;
      if (dot > 0) {
	printf("what are you mental? dot = %g,  index %d, point %g, %g, %g, vecs %g, %g, %g, %g\n",
	       dot, index, centerLine[index-1][0], centerLine[index-1][1], 
	       vec1x, vec1y, vec2x, vec2y);
	return -2;
      }
      double cross = vec1x*vec2y - vec1y*vec2x;

      double hvecx = (vec1x+vec2x)/2;
      double hvecy = (vec1y+vec2y)/2;
      
      if (fabs(cross) > 0.05) 
	{
	  length = sqrt(hvecx*hvecx + hvecy*hvecy);
	  hvecx /= length;
	  hvecy /= length;
	}
      else
	{
	  hvecx = vec1y;
	  hvecy = -vec1x;
	}

      double hcross = vec1x*hvecy - vec1y*hvecx;

      //      printf("index %d dot = %g, cross %g, hcross %g, hvec %g, %g\n", index, dot, cross, hcross, hvecx, hvecy);

      if (fabs(hcross) < 0.7)
	return -4;

      double hyplen = nextScale/fabs(hcross);

      float backup[2];
      backup[0] = centerLine[index-1][0] - vec2x;
      backup[1] = centerLine[index-1][1] - vec2y;
      getCorners(centerLine[index-1], backup, hyplen, &wideLine[2*(index-1)]);

      //if (cross > 0)
      nextScale -= deltaScale;
      index++;
    }
  // create a new point past the end.
  float extra[2];
  extra[0] =  centerLine[n-1][0] + (centerLine[n-1][0] - centerLine[n-2][0]);
  extra[1] =  centerLine[n-1][1] + (centerLine[n-1][1] - centerLine[n-2][1]);
  getCorners(centerLine[n-1], extra, nextScale, &wideLine[2*(n-1)]);
  return index;
}

void drawWideLines(int n, float centerLine[][2], float scale, float deltaScale)
{
  if (n<2)
    return;

  float wideLines[n*2][2];

  int stat = calcWideLines(n, centerLine, scale, deltaScale, wideLines);
  if (stat <= 0)
    {
      printf("\n\nbad stat from calcWideLines %d - n = %d\n", stat, n);
      return;
    }

  //  for (int ii = 0; ii < n*2; ii ++)
  //    printf("wideline %d, %g, %g\n", ii, wideLines[ii][0], wideLines[ii][1]);

  glBegin(GL_TRIANGLE_STRIP);
  for (int ii = 0; ii < n*2; ii ++)
    {
      glVertex2fv(wideLines[ii]);
    }
  glEnd();
}
*/
void setZoom(double center[2], double scale)
{
  int vp[4];
  double width, height;

  glGetIntegerv(GL_VIEWPORT, vp);

  width = (double)vp[2];
  height = (double)vp[3];
  if (width > height)
    {
      width = width/height;
      height = 1;
    }
  else
    {
      height = height/width;
      width = 1;
    }

  height *= scale;
  width *= scale;

  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  glOrtho(center[0]-width, center[0]+width, 
	  gFlipY*(center[1]-height), gFlipY*(center[1]+height), -1, 1);

  glMatrixMode (GL_MODELVIEW);
}

void init(void) 
{
  glClearColor (0.0, 0.0, 0.0, 0.0);
  glShadeModel (GL_FLAT);
  //glEnable(GL_LINE_SMOOTH);
  // init 
}

void doTick(void)
{
  static double color = 1.0;

  //  glClearColor (color, color, color, 0.0);
  //color -= 0.04;
  //if (color < 0)
  //  color = 1;
  glutPostRedisplay();
}


void drawYinYang(double center[2], double radius)
{
  double semiCenter[2];
  double fullCircle[2];
  double semiCircle[2];
  double radii[2];

  fullCircle[0] = 0;
  fullCircle[1] = 2*PIE - 0.1*PIE;

  radii[0] = radius;
  radii[1] = radius;

  drawArc(center, fullCircle, radii);

  radii[0] = radius*0.5;
  radii[1] = radius*0.5;

  semiCenter[0] = center[0] + radius*0.5;
  semiCenter[1] = center[1];
  semiCircle[0] = PIE;
  semiCircle[1] = 0;
  drawArc(semiCenter, semiCircle, radii);

  semiCenter[0] = center[0] - radius*0.5;
  semiCircle[0] = 0;
  semiCircle[1] = PIE;
  drawArc(semiCenter, semiCircle, radii);
}


void fillHalfYinYang(double center[2], double radius)
{
  // from 0 to PIE
  double semiCenter[2];
  double fullCircle[2];
  double semiCircle[2];
  double radii[2];
  GLfloat outerCircle[MAX_VERTS][2];
  GLfloat innerCircle[MAX_VERTS][2];
  GLfloat smallCircle[MAX_VERTS][2];
  int ioc, iic, isc, i;
  int joc, jic;

  fullCircle[0] = 0;
  fullCircle[1] = PIE;

  radii[0] = radius;
  radii[1] = radius;

  ioc = getArcVertices(center, fullCircle, radii, MAX_VERTS, outerCircle);

  radii[0] = radius*0.5;
  radii[1] = radius*0.5;

  semiCenter[0] = center[0] + radius*0.5;
  semiCenter[1] = center[1];
  semiCircle[1] = 0;
  semiCircle[0] = PIE;
  isc = getArcVertices(semiCenter, semiCircle, radii, MAX_VERTS, smallCircle);

  semiCenter[0] = center[0] - radius*0.5;
  semiCircle[0] = 0;
  semiCircle[1] = PIE;
  iic = getArcVertices(semiCenter, semiCircle, radii, MAX_VERTS, innerCircle);

  /* semi circle - small */
  glBegin(GL_TRIANGLE_FAN);
  glVertex2d(center[0] + radius*0.5, center[1]+0.5);
  glVertex2dv(center);
  glVertex2fv(outerCircle[0]);
  for (i = 0; i <= isc; i++) // skip last
    {
      glVertex2fv(smallCircle[i]);

    }
  glVertex2dv(center);
  glEnd();

  /* quarter circle - outer - 0..90 degrees */
  joc = 0;
  glBegin(GL_TRIANGLE_FAN);
  glVertex2dv(center);
  for (i = 0; i < ioc/2; i++)
    {
      glVertex2fv(outerCircle[joc++]);
    }
  glEnd();
  joc--;

  jic = 0;
  glBegin(GL_TRIANGLE_FAN);
  glVertex2fv(outerCircle[joc]);
  for (i = 0; i < isc/2; i++)
    {
      glVertex2fv(innerCircle[jic++]);

    }
  glEnd();

  jic--; 
  glBegin(GL_TRIANGLE_FAN);
  glVertex2fv(innerCircle[jic]);
  for (i = 0; i <= ioc/4; i++)
    {
      glVertex2fv(outerCircle[joc++]);
    }
  glVertex2fv(outerCircle[joc]);
  glEnd();
  
  glBegin(GL_TRIANGLE_FAN);
  glVertex2fv(outerCircle[joc]);
  for (i = jic; i < joc; i++)
    {
      glVertex2fv(innerCircle[jic++]);
    }
  glVertex2fv(innerCircle[jic]);
  glEnd();

  glBegin(GL_TRIANGLE_STRIP);
  for (i = joc; i < ioc; i++)
    {
      glVertex2fv(outerCircle[i]);
      glVertex2fv(innerCircle[i]);
    }
  glVertex2fv(outerCircle[ioc]);
  glEnd();
  
}

/*
  self.frame += 1
  self.SaveTo("frame%s.jpg"%(string.zfill("%d"%(self.frame),4)))
*/
void saveFrame(void)
{
  static int gScratchSize;
  static void *gScratch;
  GLint vp[4];
  Image image;
  char filename[80];
  int i;

  glGetIntegerv(GL_VIEWPORT, vp);
  if (gScratchSize == 0)
    {
      gScratchSize = vp[2]*vp[3]*4;
      gScratch = (void *)malloc(gScratchSize);
      if (!gScratch)
	return;
    }
  
  if (vp[2]*vp[3]*4 > gScratchSize)
    return;

  glReadBuffer(GL_BACK);
  glReadPixels(0,0, vp[2], vp[3], GL_RGB, GL_UNSIGNED_BYTE, gScratch);

  image.width = vp[2];
  image.height = vp[3];
  image.isGrey = 0;
  image.cmapSize = 0;
  image.data = gScratch;

  sprintf(filename, "frame%4d.jpg", gFrame);
  for (i = 0; i < strlen(filename); i++) 
    if (filename[i] == ' ') filename[i] = '0';

  WriteJPEG(filename, 100, &image);
}


void checkAndDrawTexture(int frame)
{
  static int texWidth = -1;
  static int texHeight = 0;
  GLfloat box[4][2] = {{-0.8,-0.2},{0.8,-0.2},{0.8,0.2},{-0.8,0.2}};
  GLfloat texv[4][2] = {{0,1},{1,1},{1,0},{0,0}};
  int i;
  double center[2] = {0,0};

  if ((frame < 15) || (frame > 42)) // was 10 & 37
    return;


  if (texWidth == -1)
    {
      LoadJPEGTexture("seastex.jpg",&texWidth, &texHeight);
    }

  if (texWidth < 0)
    return;

  setZoom(center, 1);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glEnable(GL_TEXTURE_2D);
  glEnable(GL_BLEND);
  glColor4f(0.0,0.0,0.0,1.0);
  
  glBegin(GL_POLYGON);
  for (i=0; i<4; i++)
    {
      glTexCoord2fv(texv[i]);
      glVertex2fv(box[i]);
    }
  glEnd();
  glDisable(GL_TEXTURE_2D);
  glDisable(GL_BLEND);
}

void checkZoomActionForFrame(int frame)
{
  static double currentCenter[2] = {0,0};
  static double currentZoom = .16;
  static double deltaCenter[2] = {0,0};
  static double deltaZoom = 0;

  if (frame == TOZOOM)
    {
      currentCenter[0] = kOuterRadius/2;
      deltaZoom = 0.014; // was 2
    }
  else if (frame == 108) // was 72.. *3/2 = 108
    {
      deltaZoom = 0.03; // was 4
    }
  else if (frame == 120) // was 96
    {
      deltaCenter[0] = 0.0;
      deltaZoom = .055; // was 7
    }
  /*
  else if (frame == 14)
    {
      double cen2[2] = {0.45,0.0};
      setZoom(cen2, 0.90);
    }
  else if (frame == 16)
    {
      double cen2[2] = {0.45,0.0};
      setZoom(cen2, 1.0);
    }
  else if (frame == 20)
    {
      double cen2[2] = {0.45,0.0};
      setZoom(cen2, 1.30);
    }
  */
  currentCenter[0] += deltaCenter[0];
  //  currentCenter[0] += deltaCenter[0];
  currentZoom += deltaZoom;
  setZoom(currentCenter, currentZoom);

  if (gVerbose > 0)
    printf("SetZoom senter %g, %g, zoom %g\n", 
	   currentCenter[0], currentCenter[1], currentZoom);

}

void doZoomingYYFrame()
{
  int i, j;
  double center[2] = {0,0};
  int blurCount = 3;
  /*
  if (gAngle < 0)
    gAngle = 360 - gAngle;
  if (gAngle > 360)
    gAngle = gAngle - 360;
  */
  if (gFrame < 152)
    checkZoomActionForFrame(gFrame);
  else if (gFrame < 200)
    gDeltaAngle -= 0.5;

  glRotated(gAngle, 0, 0, 1);
  gAngle -= gDeltaAngle;

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  for (i = 0; i < blurCount; i++)
    {
      glColor4f(0.0,0.0,0.0,0.2);
      fillHalfYinYang(center, kOuterRadius);
      glRotated(i+1, 0, 0, 1);
    }

  glDisable(GL_BLEND);

  glColor4f(0.0,0.0,0.0,0.7);
  fillHalfYinYang(center, kOuterRadius);


  glColor4f(0,0,0,1);
  glLineWidth(4.0);
  drawYinYang(center, kOuterRadius);

  glEnable(GL_BLEND);

  for (i = 0; i < blurCount; i++)
    {
      glRotated(i+1, 0, 0, 1);
      glColor4f(0.0,0.0,0.0,0.2);
      fillHalfYinYang(center, kOuterRadius);
    }

  glDisable(GL_BLEND);
}

double Distance(double center[2], double endPoint[2])
{
  double distance, dx, dy;

  dx = center[0] - endPoint[0];
  dy = center[1] - endPoint[1];
  
  distance = sqrt(dx*dx+dy*dy);

  return distance;
}

// find a point on a circle and the tangent to a second point.
void getMagicPoint(double center[2], double radius, double endPoint[2],
		   double tanPoint[2])
{
  double distance, side1;
  double localAngle, delAng;
  double difference;

  distance = Distance(center, endPoint);
  side1 = sqrt(distance*distance + radius*radius);
  
  localAngle = PIE;
  if (endPoint[0] < center[0])
    localAngle = 0;
  delAng = PIE/8.0;
  difference = 1.0;

  while (difference > 0.001)
    {
      double newDist;
      double newAngle;

      newAngle = localAngle + delAng;
      tanPoint[0] = center[0] + radius * cos(newAngle);
      tanPoint[1] = center[1] + radius * sin(newAngle);

      newDist = Distance(tanPoint, endPoint);

      if (newDist > side1)
	{
	  difference = newDist - side1;
	  localAngle += delAng;
	}
      else
	delAng = delAng / 2;
      
      // printf("magic angle %8.4f newDist %8.4f side1 %8.4f, point %g, %g\n",
      //   localAngle, newDist, side1, tanPoint[0], tanPoint[1]);
    }
  
}

/********
frame 171, delta angle  -18.000 angle  298.000
frame 172, delta angle  -18.000 angle  316.000
frame 173, delta angle  -18.000 angle  334.000
frame 174, delta angle  -18.000 angle  352.000
*/
void doUnrollingYYFrame()
{
  int i, j;
  double center[2] = {0,0};
  int blurCount = 3;
  int passes = 0;
  double line;
  double angle;
  double angles[2];
  double radii[2];
  double otherCenter[2];
  double thirdCenter[2];
  double dist;
  static int rotation = 0;
  double equation[4] = {0,-1,0,0};
  double equation2[4] = {1,0,0,0};
  
  // fro start3
  if (gStart3)
  {
    double center2[2] = {0,0};

    glClearColor (1.0, 1.0, 1.0, 0.0);


    center2[0] = kOuterRadius/2;
    setZoom(center2, 4);
  }

  /*
   * second radius is at 45 degrees and 2*kOuterRadius away
   * which means it is center +2*RAD2*kOuterRadius, -2*RAD2*kOuterRadius
   *
   * draw the twelfth arc and lines first.
   */
  angle = ((int)(gAngle)) % 360;
  if (angle < 0)
    angle = angle + 360;

  if ((angle+0.0001 >= 0) && (angle < fabs(gDeltaAngle)))
    rotation++;

  // phase 0 - 
  // phase 1 - 
  if (gVerbose)
    printf(" frame %d, rotation %d, angle %g, gAngle %g\n", 
	   gFrame, rotation, angle, gAngle);

  gAngle -= gDeltaAngle;

  radii[0] = radii[1] = kOuterRadius;
  otherCenter[0] = sqrt(3)*kOuterRadius;
  otherCenter[1] = -kOuterRadius;

  glLineWidth(4.0);

  // take care of right side
  if (((rotation == 0) && (angle > 330)) || ((rotation == 1) && (angle <= 30)))
    {
      double twelfth;

      twelfth = angle - 330;
      if (twelfth < 0)
	twelfth += 360;

      if (twelfth > 60)
	twelfth = 60;

      angles[0] = (5.0/12.0)*2*PIE - twelfth/180.0 * PIE ;
      angles[1] = (5.05/12.0)*2*PIE;

      drawArc(otherCenter, angles, radii);
    }      
  else if ((rotation == 1) && ((angle > 30) && (angle <= 330)))
    {
      double lend;

      angles[0] = 0.5 *PIE;
      angles[1] = (5.05/12.0)*2*PIE;

      drawArc(otherCenter, angles, radii);      
      
      lend = (angle - 30)/180.0 * PIE + otherCenter[0];
      glBegin(GL_LINES);
      glVertex2d(otherCenter[0], 0);
      glVertex2d(lend, 0);
      glEnd();
    }
  else if (((rotation == 1) && (angle > 330)) || ((rotation == 2) && (angle <= 80)))
    {
      double innerCenter[2];
      double endPoint[2];
      double magicPoint[2];
      double twelfth;

      twelfth = angle - 330;
      if (twelfth < 0)
	twelfth += 360;

      if (twelfth < 55)
	{
	  //stilted = 1.0 - cos(twelfth/180.0 * PIE);
	  angles[0] = 0.498 *PIE;
	  angles[1] = (5.0/12.0)*2*PIE - (twelfth*0.8)/180.0 * PIE + 0.03;

	  drawArc(otherCenter, angles, radii);

	  angles[1] -= 0.03;

	  endPoint[0] = otherCenter[0] + radii[0]*cos(angles[1]);
	  endPoint[1] = otherCenter[1] + radii[0]*sin(angles[1]);
	  // printf("cos - %g, %g, %g\n", angles[1], endPoint[0], endPoint[1]);
	}
      else
	{
	  endPoint[0] = otherCenter[0];
	  endPoint[1] = 0;
	}

      innerCenter[0] = 0.5 * kOuterRadius * cos(angle/180.0*PIE);
      innerCenter[1] = 0.5 * kOuterRadius * sin(angle/180.0*PIE);
      getMagicPoint(innerCenter, kOuterRadius/2.2, endPoint, magicPoint);

      glBegin(GL_LINES);
      glVertex2d(magicPoint[0], magicPoint[1]);
      glVertex2d(endPoint[0], endPoint[1]);
      glVertex2d(otherCenter[0], 0);
      glVertex2d(6*kOuterRadius, 0);
      glEnd();
    }
  else if (rotation >= 1)
    {
      glBegin(GL_LINES);
      glVertex2d(-0.1, 0);
      glVertex2d(6*kOuterRadius, 0);
      glEnd();
    }

  // left side *********************************************************

  thirdCenter[0] = -sqrt(3)*kOuterRadius;
  thirdCenter[1] = kOuterRadius;

  if (((rotation == 1) && (angle > 330))
	   || ((rotation == 2) && (angle <= 30)))
    {
      double twelfth;

      twelfth = angle - 330;
      if (twelfth < 0)
	twelfth += 360;

      if (twelfth > 60)
	twelfth = 60;

      angles[0] = (11.0/12.0)*2*PIE - twelfth/180.0 * PIE ;
      angles[1] = (11.05/12.0)*2*PIE;

      drawArc(thirdCenter, angles, radii);
    }
  else if (((rotation == 2) && (angle > 30) && (angle <= 150)))
    {
      double lend, delAng;

      angles[0] = (9.0/12.0)*2*PIE;
      angles[1] = (11.05/12.0)*2*PIE;

      drawArc(thirdCenter, angles, radii);      
      

      delAng = angle - 30; 
      if (delAng < 0)
	delAng += 360;

      lend =  thirdCenter[0] - delAng/180.0 * PIE * 1.5;
      glBegin(GL_LINES);
      glVertex2d(thirdCenter[0], 0);
      glVertex2d(lend, 0);
      glEnd();
    }
  else if ((rotation == 2) && (angle > 150) && (angle <= 260))
    {
      double innerCenter[2];
      double endPoint[2];
      double magicPoint[2];
      double twelfth;

      twelfth = angle - 150;
      if (twelfth < 0)
	twelfth += 360;


      if (twelfth < 55)
	{
	  angles[0] = 1.498 *PIE;
	  angles[1] = (11.0/12.0)*2*PIE - (twelfth*0.8)/180.0 * PIE + 0.03;

	  drawArc(thirdCenter, angles, radii);

	  angles[1] -= 0.03;

	  endPoint[0] = thirdCenter[0] + radii[0]*cos(angles[1]);
	  endPoint[1] = thirdCenter[1] + radii[0]*sin(angles[1]);
	}
      else
	{
	  endPoint[0] = thirdCenter[0];
	  endPoint[1] = 0;
	}

      // take car of right side
      innerCenter[0] = 0.5 * kOuterRadius * cos(angle/180.0*PIE);
      innerCenter[1] = 0.5 * kOuterRadius * sin(angle/180.0*PIE);
      getMagicPoint(innerCenter, kOuterRadius/2.2, endPoint, magicPoint);

      glBegin(GL_LINES);
      glVertex2d(magicPoint[0], magicPoint[1]);
      glVertex2d(endPoint[0], endPoint[1]);
      glVertex2d(thirdCenter[0], 0);
      glVertex2d(-6*kOuterRadius, 0);
      glEnd();
    }
  else if (rotation > 1)
    {
      glBegin(GL_LINES);
      glVertex2d(0.1, 0);
      glVertex2d(-6*kOuterRadius, 0);
      glEnd();     
    }

  if ((rotation == 0) ||  ((rotation == 1) && (angle <= 150)))
    {
      angles[0] = angle/180.0 * PIE - 1.05*PIE;
      if (angles[0] < 0)
	angles[0] += 2*PIE;
      angles[1] = 330.0/360.0*2*PIE;
      //      if ((angles[0] < angles[1]) && (rotation <= 1))
      drawArc(center, angles, radii);
    }

  if ((rotation == 3) && (angle > 80))
    {
      gFrame = 10000;
      return;
    }

  // we do not need to draw the uppler left quad anymore, just below the line
  if (((rotation == 2) && (angle >= 260)) || (rotation > 2))
    passes = 1;
  else if ((rotation == 2) && (angle >= 180))
    passes = 2;
  else // no clipping
    passes = -1;
    
  while ((passes == -1) || (passes > 0))
    {
      if (passes == 2)
	{
	  glEnable(GL_CLIP_PLANE0);
	  glEnable(GL_CLIP_PLANE1);
	  equation[1] = 1;
	  equation2[0] = -1;
	}
      else if (rotation > 2) // passes == 1
	{
	  glEnable(GL_CLIP_PLANE0);
	  glEnable(GL_CLIP_PLANE1);
	  equation[1] = -1;
	  equation2[0] = 1;
	}
      else if (passes == 1)
	{
	  glEnable(GL_CLIP_PLANE0);
	  equation[1] = -1;
	}

      glLoadIdentity();

      if (gVerbose)
	printf("passes %d, eq1 0, %g, plane1 %g, 0\n", 
	       passes, equation[1], equation2[0] );

      glClipPlane(GL_CLIP_PLANE0, equation ); // below X axis (0,-1)
      glClipPlane(GL_CLIP_PLANE1, equation2 ); // left of Y axis (1,0) 

      glRotated(angle, 0, 0, 1);

      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

      for (i = 0; i < blurCount; i++)
	{
	  glColor4f(0.0,0.0,0.0,0.2);
	  fillHalfYinYang(center, kOuterRadius);
	  glRotated(i+1, 0, 0, 1);
	}

      glDisable(GL_BLEND);

      glColor4f(0.0,0.0,0.0,0.7);
      fillHalfYinYang(center, kOuterRadius);

      glEnable(GL_BLEND);

      for (i = 0; i < blurCount; i++)
	{
	  glRotated(i+1, 0, 0, 1);
	  glColor4f(0.0,0.0,0.0,0.2);
	  fillHalfYinYang(center, kOuterRadius);
	}

      glDisable(GL_BLEND);
      glDisable(GL_CLIP_PLANE0);
      glDisable(GL_CLIP_PLANE1);

      passes--;
    }
}

void doYangFrame()
{
  GLfloat vertices[MAX_VERTS][2];
  double center[2] = {0,0};
  double radii[2] = {4,4};
  double angles[2] = {PIE,2*PIE};
  static double height = 6;
  int blurCount = 3;
  float alpha = 1;
  int segments, i;

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  center[1] = height;
  height -= 0.09;
  radii[0] = 1.5*PIE - PIE/16.0;
  radii[1] = 1.5*PIE + PIE/16.0;
  dAngle = 0.04;
  segments = getArcVertices(center, angles, radii, MAX_VERTS, vertices);
  dAngle = 0.08;  
  glColor4f(1.0,1.0,1.0,alpha);

  glBegin(GL_TRIANGLE_FAN);
  glVertex2d(0,1.5);
  for (i = 0; i <= segments; i++) // skip last
    {
      glVertex2fv(vertices[i]);
    }
  glEnd();

  for (i = 0; i < blurCount; i++)
    {
      int j;
      glTranslated(0,-0.03,0);
      glColor4f(1.0,1.0,1.0,0.3);
      glBegin(GL_TRIANGLE_FAN);
      glVertex2d(0,1.5);
      for (j = 0; j <= segments; j++) // skip last
	{
	  glVertex2fv(vertices[j]);
	}
      glEnd();
    }
  glDisable(GL_BLEND);
}

void display(void)
{
  int c;
  if (gFrame >= gLastFrame)
      exit(0);

  gFrame++;

  if (gFrame == TOZOOM)
    glClearColor (1.0, 1.0, 1.0, 0.0);

  // Clear the window with current clearing color
  glClear(GL_COLOR_BUFFER_BIT);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  if (gFrame < TOZOOM)
    doYangFrame();
  else if (gFrame < UNROLL)
    doZoomingYYFrame();
  else
    doUnrollingYYFrame();

  checkAndDrawTexture(gFrame);

  // Flush drawing commands
  glFlush();
  if (gSaveAnim) 
    {
      saveFrame();
    }
  glutSwapBuffers();
}

void reshape (int w, int h)
{
  double wide, high;
  // Prevent a divide by zero
  if(h == 0)
    h = 1;

  glViewport (0, 0, (GLsizei) w, (GLsizei) h); 
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  wide = (double)w;
  high = (double)h;
  if (w > h)
    {
      wide = wide/high;
      high = 1;
    }
  else
    {
      high = high/wide;
      wide = 1;
    }
  glOrtho(-wide, wide, -high*gFlipY, high*gFlipY, -1, 1);

  glMatrixMode (GL_MODELVIEW);
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:
         exit(0);
         break;
   }
}

int main(int argc, char** argv)
{
  int i;
  char *texfile = 0;
  int winSizeX = 704;
  int winSizeY = 576;

  glutInit(&argc, argv);
  
  for (i = 1; i < argc; i++)
    {
      if (argv[i][0] != '-') /* ignore args with leading - */
	{
	    texfile = argv[i];
	}
      else if (!strcmp("-save",argv[i]))
	{
	  gSaveAnim = 1;
	}
      else if (!strcmp("-flip",argv[i]))
	{
	  gFlipY = -1;
	}
      else if (!strcmp("-last",argv[i]))
	{
	  i++; if (i < argc)
	    gLastFrame = atoi(argv[i]);
	  else
	    gLastFrame = 3;
	}
      else if (!strcmp("-start3",argv[i]))
	{
	  // frame 171, delta angle  -18.000 angle  298.000
	  //  frame 214, angle 336, gAngle -1464
	  gAngle = -48;
	  gDeltaAngle = -kDeltaPeriod;
	  gFrame = 211;
	  gStart3 = 1;
	}
      else if (!strcmp("-big",argv[i]))
	{
	  winSizeX = 1024;
	  winSizeY = 838;
	}
      else if (!strcmp("-v",argv[i]))
	{
	  gVerbose = 1;
	}
      else
	{
	  printf("YOU GOOFED UP! - %s\n", argv[i]);
	  exit(0);
	}
    }

   glutInitDisplayMode ( GLUT_DOUBLE | GLUT_RGB);
   glutInitWindowSize (winSizeX, winSizeY); 
   glutCreateWindow (argv[0]);
   init ();
   glutDisplayFunc(display); 
   glutIdleFunc(doTick); 
   glutReshapeFunc(reshape);
   glutKeyboardFunc(keyboard);
   glutMainLoop();
   return 0;
}
