/*
	ampex2

	mk@lemo.dk, 29-jan-2025

*/


#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <fcntl.h>
#include <math.h>
#include <assert.h>
#include <GL/freeglut_ext.h>
#include "spole5.xpm"

extern void bbox(double ,double *,double *,double *,double *,char *);
extern void stroke(double ,double ,double ,double ,char *);

#define MirrorY 1175.0
#define TopReelX 233.0
#define TopReelY 267.0
#define TopReelOuterR 215.0
#define TopReelInnerR 94.0
#define TopReelLabelWidth 150.0
#define TopReelLabelHeight 50.0
#define LABELTEXT "Help3 GA4"
#define TopReelLabelDistance 150.0
#define TopCornerX 484.0
#define TopCornerY 247.0
#define TopCornerOuterR 11.0
#define TopCornerInnerR 5.0
#define TopChamperInX 396.0
#define TopChamperInY 483.0
#define TopChamperInInnerR 9.0
#define TopChamperInOuterR 34.5
#define TopChamperOuter1X 389.0
#define TopChamperOuter1Y 488.0
#define TopChamperOuter2X 725.0
#define TopChamperOuter2Y 29.0
#define TopChamperOuter3X 807.0
#define TopChamperOuter3Y 95.0
#define TopChamperOuter4X 472.0
#define TopChamperOuter4Y 555.0
#define TopChamperInner1X 397.0
#define TopChamperInner1Y 496.0
#define TopChamperInner2X 728.0
#define TopChamperInner2Y 46.0
#define TopChamperInner3X 793.0
#define TopChamperInner3Y 98.0
#define TopChamperInner4X 463.0
#define TopChamperInner4Y 549.0
#define TopChamperOutX 473.0
#define TopChamperOutY 536.0
#define TopChamperOutR 10.0
#define Head1X 546.0
#define Head1Y 579.0
#define Head2X 546.0
#define Head2Y 543.0
#define Head3X 577.0
#define Head3Y 523.0
#define Head4X 601.0
#define Head4Y 523.0
#define Head5X 631.0
#define Head5Y 543.0
#define Head6X 631.0
#define Head6Y 579.0
#define CapstanX 706.0
#define CapstanY 593.0
#define CapstanR 43.0
#define BottomReelX 233.0
#define BottomReelY (MirrorY-267.0)
#define BottomReelOuterR 215.0
#define BottomReelInnerRx 94.0
#define BottomReelInnerR 84.0
#define BottomCornerX 484.0
#define BottomCornerY (MirrorY-247.0)
#define BottomCornerOuterR 11.0
#define BottomCornerInnerR 5.0
#define BottomChamperInX 396.0
#define BottomChamperInY (MirrorY-483.0)
#define BottomChamperInOuterR 34.5
#define BottomChamperInInnerR 9.0
#define BottomChamperOuter1X 389.0
#define BottomChamperOuter1Y (MirrorY-488.0)
#define BottomChamperOuter2X 725.0
#define BottomChamperOuter2Y (MirrorY-29.0)
#define BottomChamperOuter3X 807.0
#define BottomChamperOuter3Y (MirrorY-95.0)
#define BottomChamperOuter4X 472.0
#define BottomChamperOuter4Y (MirrorY-555.0)
#define BottomChamperInner1X 397.0
#define BottomChamperInner1Y (MirrorY-496.0)
#define BottomChamperInner2X 728.0
#define BottomChamperInner2Y (MirrorY-46.0)
#define BottomChamperInner3X 793.0
#define BottomChamperInner3Y (MirrorY-98.0)
#define BottomChamperInner4X 463.0
#define BottomChamperInner4Y (MirrorY-549.0)
#define BottomChamperOutX 473.0
#define BottomChamperOutY (MirrorY-536.0)
#define BottomChamperOutR 10.0

/*  status:

*/
#define TAPE_IDLE 0
#define TAPE_FORWARD 10
#define FORWARD_ACCELERATE 11
#define FORWARD_KEEP 12
#define FORWARD_DECELERATE 13

#define TAPE_REVERSE 20
#define REVERSE_ACCELERATE 21
#define REVERSE_KEEP 22
#define REVERSE_DECELERATE 23

#define TAPE_REWIND 30
#define REWIND_ACCELERATE 31
#define REWIND_KEEP 32
#define REWIND_DECELERATE 33

static int status=0;

/* speed, in m/s */

#define READSPEED (36.0*0.0254)
#define REWINDSPEED (180.0*0.0254)
// It can accelerate to READSPEED in 0.01 secs
// capstanAcceleration = 36*0.0254/0.01 = 91.44 m/s²
// However, we want to do it in one framerate (1/60 sec):
#define CAPSTANACCELERATION (36.0*0.0254*60.0)
#define XMAX 830
#define YMAX 1170
double secs,lastsecs,dsecs,inRadius,outRadius,inRotation,outRotation;
double capstanSpeed=0.0;
double capstanAcceleration=0;
//double capstanAcceleration=0;
double inSpeed=0.0;
double inAcceleration=0.0;
double inRatio=0.0;
double outSpeed=0.0;
double outAcceleration=0.0;
double outRatio=0.0;
double UAKK;

#define wXMAX 247
#define wYMAX 350

/* pixels per m 215/0.1325=1622.64 pixels/m*/
#define PIXELSPERM (BottomReelOuterR/0.1325)
#define THICKNESS (2.43e-3*0.0254)
#define TAPELENGTH (2400.0*12.0*0.0254)
/* help3 block: 400 words
   density 200/556 cpi
   gap 0.75"
   6 bit + parity / character

record: 200 cpi: 400*7/200 + 0.75 = 14.75" = 0.37465 m
        556 cpi: 400*7/556 + 0.75 = 5.79" =  0.147 m

champer length: 34.42 cm
width:          5.13 cm
*/
#define BLOCKLEN ((400.0*7.0/200.0+0.75)*0.0254)
// = 0.37465 m
#define GAPLEN (0.75*0.0254)
static double taperead=0.0,readstart,tapeappetite,tapeadjust;
#define CHAMPERLENGTH 0.3442
#define CHAMPERWIDTH 0.0513
#define MAXCHAMPERTAPELENGTH (2.0*CHAMPERLENGTH-CHAMPERWIDTH*0.5+CHAMPERWIDTH*M_PI)
double inTape=MAXCHAMPERTAPELENGTH*0.5;
double outTape=MAXCHAMPERTAPELENGTH*0.5;
double inError=0.0;
double outError=0.0;
static double thickness=THICKNESS;
static double OUTlength=0.0;
static double INlength=TAPELENGTH;
static double radius0=0.113/2.0;
static struct timespec time0,time1;

/* The number of our GLUT window */
int window; 
int window_width, window_height;
int fullscreen=0;
GLdouble window_aspect;

#define SQR(x)  ((x)*(x))
#define SIGN(x) ( (x)<0.0?-1.0:((x)>0.0?1.0:0.0) )


GLuint loop;             // general loop variable

int xmin, xmax, ymin, ymax;

GLfloat LightAmbient[]  = {0.5, 0.5, 0.5, 1.0}; 
GLfloat LightDiffuse[]  = {1.0, 1.0, 1.0, 1.0}; 
GLfloat LightPosition[] = {0.0, 0.0, 2.0, 1.0};

/* storage for one texture  */
GLuint texture[1];

/* Image type - contains height, width, and data */
struct Image {
    unsigned int sizeX;
    unsigned int sizeY;
    char *data;
};
typedef struct Image Image;

int ImageLoad(const char **xpm, Image *image) {
    unsigned long i,r,c,size;                    // standard counter.
    unsigned int ncolors,charsPerPixel,index,*p,*clookup;

    sscanf(xpm[0], "%u %u %u %u",&image->sizeX,&image->sizeY,&ncolors,&charsPerPixel);

    clookup=(unsigned int *) malloc(sizeof(*clookup)*256*256);

    for(i=0;i<65536;i++) clookup[i]=0;
    for(i=1;i<=ncolors;i++)
    {
      index=xpm[i][0]+xpm[i][1]*256;
      if(xpm[i][3]=='c')
      {
	if(xpm[i][5]=='#')
	{
	  sscanf(xpm[i]+6, "%X", &clookup[index]);
	  clookup[index] |= 0xFF000000;
	}
	else if(xpm[i][5]=='N')
	{
	  clookup[index]=0x00FFFFFF;
	}
	else if(xpm[i][5]=='b')
	{
	  clookup[index]=0xFF000000;
	}
      }
    }
    size = image->sizeX * image->sizeY * 4;
    image->data = (char *) malloc(size);
    p = (unsigned int *) (image->data);
    for(r=0;r<image->sizeY;r++)
    {
      for(c=0;c<image->sizeX;c++)
      {
	index=xpm[ncolors+1+r][c*2] + xpm[i+r][c*2+1]*256;
	p[r*image->sizeX+c]=clookup[index];
      }
    }
#ifdef uakk
    p = (unsigned int *) image->data;
    for(r=0;r<image->sizeY;r++)
      for(c=0;c<image->sizeX;c++)
      {
	printf("%4ld %4ld %8.8X\n",r,c,(*p));
	p++;
      }
#endif
    free((char *) clookup);
    
    return 1;
}

static double seconds()
{
  double td;
  long tn;
  clock_gettime(CLOCK_MONOTONIC, &time1);
  tn=time1.tv_nsec - time0.tv_nsec;
  td=time1.tv_sec - time0.tv_sec;
  if(tn<0)
  {
    tn += 1000000000L;
    td -= 1.0;
  }
  td += ((double)tn)*1e-9;
  return(td);
}

static int QUAREQ2(double A, double B, double C, double *x1, double *x2)
{
  double D;
  int ret=0;
  if(A==0.0)
  {
    if(B==0.0)
      ret=1;
    else
    {
      *x1 = -C/A;
      *x2 = *x1;
    }
  }
  else
  {
    D=SQR(B)-4.0*A*C;
    if(D<0.0)
      ret=1;
    else
    {
      *x1 = (-B - ((B<0.0)?-1.0:1.0)*sqrt(D))/2.0/A;
      *x2 = C/A/(*x1);
    }
  }
  return(ret);
}

static double radius2Length(double r)
{
  return((M_PI/thickness)*SQR(r)+M_PI*r-SQR(radius0)*M_PI/thickness);
}

static double length2Thickness(double l, double r)
{
  return(M_PI*(SQR(r)-SQR(radius0))/(l-M_PI*r));
}

static double length2Radius(double l)
{
  double A,B,C,x1,x2;
  A=M_PI/thickness;
  B=M_PI;
  C=-(SQR(radius0)*M_PI/thickness)-l;
  QUAREQ2(A, B, C, &x1, &x2);
  return(x2);
}

static double rotation2Length(double r)
{
  return(M_PI*thickness*SQR(r)+(2.0*M_PI*radius0)*r);
}

static double length2Rotation(double l)
{
  double A,B,C,x1,x2;
  A=M_PI*thickness;
  B=2.0*M_PI*radius0;
  C=-l;
  QUAREQ2(A, B, C, &x1, &x2);
  return(x2);
}


static void disk(GLdouble x0, GLdouble y0, GLdouble z0,GLdouble r1, GLdouble r2)
{
  GLdouble x1,y1,x2,y2,v,lastx1,lasty1,lastx2,lasty2;

  lastx1=x0+r1;
  lasty1=y0;
  lastx2=x0+r2;
  lasty2=y0;
  for(v=5;v<=360;v+=5)
  {
    x1=x0+r1*cos(v/180.0*M_PI);
    y1=y0+r1*sin(v/180.0*M_PI);
    x2=x0+r2*cos(v/180.0*M_PI);
    y2=y0+r2*sin(v/180.0*M_PI);
    glVertex3d(lastx1,lasty1,z0);
    glVertex3d(lastx2,lasty2,z0);
    glVertex3d(x1,y1,z0);
    glVertex3d(lastx2,lasty2,z0);
    glVertex3d(x2,y2,z0);
    glVertex3d(x1,y1,z0);
    lastx1=x1;
    lasty1=y1;
    lastx2=x2;
    lasty2=y2;
  }
}

static void circle(GLdouble x0, GLdouble y0, GLdouble r, GLdouble v0, GLdouble v1)
{
  GLdouble lastx,lasty,x,y,v;
  int i,n;

  n=r*2;
  lastx=x0+r*cos(v0/180.0*M_PI);
  lasty=y0-r*sin(v0/180.0*M_PI);
  for(i=1;i<=n;i++)
  {
    v=v0+(v1-v0)*((double)i)/((double) n);
    x=x0+r*cos(v/180.0*M_PI);
    y=y0-r*sin(v/180.0*M_PI);
    glVertex3d(lastx,lasty,0.0);
    glVertex3d(x,y,0.0);
    lastx=x;
    lasty=y;
  }
}


    
// Load Bitmaps And Convert To Textures
void LoadGLTextures() {	
    // Load Texture
    Image *image1;
    
    // allocate space for texture
    image1 = (Image *) malloc(sizeof(Image));
    if (image1 == NULL) {
	printf("Error allocating space for image");
	exit(0);
    }

    if (!ImageLoad(spole5, image1)) {
	exit(1);
    }        

    // Create Texture	
    glGenTextures(1, &texture[0]);
    glBindTexture(GL_TEXTURE_2D, texture[0]);   // 2d texture (x and y size)

    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // scale linearly when image bigger than texture
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // scale linearly when image smalled than texture

    // 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image, 
    // border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image1->sizeX, image1->sizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, image1->data);
};

static void intersectionLineCircle(double a1, double c1,
                                   double x1, double y1, double r1,
				   double *xi1, double *yi1,
				   double *xi2, double *yi2)
{
  double A,B,C,d,tmp;
  A=(1.0+SQR(a1));
  B=(-2.0*x1+2.0*a1*(y1+c1));
  C=SQR(x1)+SQR(y1+c1)-SQR(r1);
  d=SQR(B)-4.0*A*C;
  if(d<0)
  {
    fprintf(stderr, "no intersection\n");
    exit(-1);
  }
  *xi1 = (-B+sqrt(d))/2.0/A;
  *xi2 = (-B-sqrt(d))/2.0/A;
  if((*xi1) > (*xi2))
  {
    tmp=*xi1;
    *xi1=*xi2;
    *xi2=tmp;
  }
  *yi1 = -c1-a1*(*xi1);
  *yi2 = -c1-a1*(*xi2);
}

static void intersectionLines(double a1, double c1,
                              double a2, double c2,
			      double *x, double *y)
{
  *x = (c1-c2)/(a2-a1);
  *y = -c1-a1*(*x);
}

static void intersectionCircles(double x1, double y1, double r1,
                                double x2, double y2, double r2,
				double *xi1, double *yi1,
				double *xi2, double *yi2)
{
  double R,tmp;
  /* https://math.stackexchange.com/questions/256100/how-can-i-find-the-points-at-which-two-circles-intersect */
  R=sqrt(SQR(x1-x2)+SQR(y1-y2));
  *xi1 = (x1+x2)/2.0 + (SQR(r1)-SQR(r2))/2.0/SQR(R)*(x2-x1)
        +0.5*sqrt(2.0*(SQR(r1)+SQR(r2))/SQR(R)-SQR(SQR(r1)-SQR(r2))/SQR(SQR(R))-1.0)*(y2-y1);
  *xi2 = (x1+x2)/2.0 + (SQR(r1)-SQR(r2))/2.0/SQR(R)*(x2-x1)
        -0.5*sqrt(2.0*(SQR(r1)+SQR(r2))/SQR(R)-SQR(SQR(r1)-SQR(r2))/SQR(SQR(R))-1.0)*(y2-y1);
  *yi1 = (y1+y2)/2.0 + (SQR(r1)-SQR(r2))/2.0/SQR(R)*(y2-y1)
        +0.5*sqrt(2.0*(SQR(r1)+SQR(r2))/SQR(R)-SQR(SQR(r1)-SQR(r2))/SQR(SQR(R))-1.0)*(x1-x2);
  *yi2 = (y1+y2)/2.0 + (SQR(r1)-SQR(r2))/2.0/SQR(R)*(y2-y1)
        -0.5*sqrt(2.0*(SQR(r1)+SQR(r2))/SQR(R)-SQR(SQR(r1)-SQR(r2))/SQR(SQR(R))-1.0)*(x1-x2);
  if((*xi1)>(*xi2))
  {
    tmp=(*xi1); *xi1 = (*xi2); *xi2=tmp;
    tmp=(*yi1); *yi1 = (*yi2); *yi2=tmp;
  }
}

static void points2Line(double x1, double y1,
                        double x2, double y2,
			double *a, double *c)
{
  *a = (y1-y2)/(x2-x1);
  *c = -(*a)*x1-y1;
}

static void twoCirclesTangent(double x1, double y1, double r1,
                              double x2, double y2, double r2,
			      int transverse,
			      double *xi11, double *yi11,
			      double *xi12, double *yi12,
			      double *xi21, double *yi21,
			      double *xi22, double *yi22)
{
  /* https://math.stackexchange.com/questions/1662110/common-tangent-to-two-circles */
  double a,c,xr,yr,ca,cc,cx1,cy1,cx2,cy2,ca2,cc2,x3,y3,r3,angle;
  points2Line(x1,y1,x2,y2,&ca,&cc);
  angle=atan2(y2-y1,x2-x1)+M_PI_2;
  cx1=x1+r1*cos(angle);
  cy1=y1+r1*sin(angle);
  cx2=x2+r2*cos(angle+(transverse?M_PI:0));
  cy2=y2+r2*sin(angle+(transverse?M_PI:0));
  points2Line(cx1,cy1,cx2,cy2,&ca2,&cc2);
  intersectionLines(ca,cc,ca2,cc2,&xr,&yr);
  x3=(x2+xr)/2.0;
  y3=(y2+yr)/2.0;
  r3=sqrt(SQR(xr-x2)+SQR(yr-y2))/2.0;
  intersectionCircles(x2,y2,r2,x3,y3,r3,xi21,yi21,xi22,yi22);
  x3=(x1+xr)/2.0;
  y3=(y1+yr)/2.0;
  r3=sqrt(SQR(xr-x1)+SQR(yr-y1))/2.0;
  intersectionCircles(x1,y1,r1,x3,y3,r3,xi11,yi11,xi12,yi12);
}

/*
void Screen2Pixel(int screenx, int screeny, int *x, int *y)
{
  *x = ((GLdouble) screenx)/((GLdouble) window_width)*(xmaxa-xmina)+xmina;
  *y = ((GLdouble) screeny)/((GLdouble) window_height)*(ymaxa-ymina)+ymina;
}
*/

GLvoid InitGL(GLsizei Width, GLsizei Height)
{
  // printf("InitGL: %d %d\n", Width, Height);

  window_width=Width;
  window_height=Height;
  window_aspect = ((GLdouble) Width)/((GLdouble) Height)*((GLdouble) YMAX)/((GLdouble) XMAX);

  LoadGLTextures();				// Load The Texture(s) 
  glClearColor(1.0, 1.0, 1.0, 1.0);	// Clear The Background Color To White 
  glClearDepth(0.9);				// Enables Clearing Of The Depth Buffer
  glDepthFunc(GL_LESS);			// The Type Of Depth Test To Do
  glEnable(GL_DEPTH_TEST);			// Enables Depth Testing
  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);

  glShadeModel(GL_SMOOTH);			// Enables Smooth Color Shading
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glDisable(GL_BLEND);
  glEnable(GL_LINE_SMOOTH);
    
  glMatrixMode(GL_MODELVIEW);

  glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
  glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
  glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
  glEnable(GL_LIGHT1);
}

GLvoid ReSizeGLScene(GLsizei Width, GLsizei Height)
{
  if (Height==0) Height=1;
  // printf("ReSize: %d %d\n", Width, Height);
  window_width=Width;
  window_height=Height;
  window_aspect = ((GLdouble) Width)/((GLdouble) Height)*((GLdouble) YMAX)/((GLdouble) XMAX);

  glViewport(0, 0, window_width, window_height);

}

/* The main drawing function. */

static void TapeUpdate()
{
  double total;
  secs=seconds();
  dsecs=secs-lastsecs;
  lastsecs=secs;
  switch(status)
  {
    case TAPE_IDLE:
      break;

    case FORWARD_ACCELERATE:
      if(capstanSpeed>READSPEED)
      {
	capstanAcceleration=0.0;
	capstanSpeed=READSPEED;
	status=FORWARD_KEEP;
      }
      break;
    case FORWARD_KEEP:
      if((taperead-readstart+GAPLEN)>=tapeappetite)
      {
	capstanAcceleration=-CAPSTANACCELERATION;
	status=FORWARD_DECELERATE;
      }
      break;
    case FORWARD_DECELERATE:
      if(capstanSpeed<0.01)
      {
	capstanSpeed=0;
	capstanAcceleration=0;
	tapeadjust=readstart+tapeappetite-taperead;
	printf("tapeadjust: %.8f\n",tapeadjust);
	taperead+=tapeadjust;
	inTape-=tapeadjust;
	outTape+=tapeadjust;
	status=TAPE_IDLE;
      }
      break;

    case REVERSE_ACCELERATE:
      if(capstanSpeed<(-READSPEED))
      {
	capstanAcceleration=0.0;
	capstanSpeed=-READSPEED;
	status=REVERSE_KEEP;
      }
      break;
    case REVERSE_KEEP:
      if((readstart-taperead+GAPLEN)>=tapeappetite)
      {
	capstanAcceleration=CAPSTANACCELERATION;
	status=REVERSE_DECELERATE;
      }
      break;
    case REVERSE_DECELERATE:
      if(capstanSpeed>-0.01)
      {
	capstanSpeed=0;
	capstanAcceleration=0;
	tapeadjust=taperead-readstart+tapeappetite;
	printf("tapeadjust: %.8f\n",tapeadjust);
	taperead-=tapeadjust;
	inTape+=tapeadjust;
	outTape-=tapeadjust;
	status=TAPE_IDLE;
	tapeadjust=taperead-readstart-tapeappetite;
      }
      break;

    case REWIND_ACCELERATE:
      if(capstanSpeed<(-REWINDSPEED))
      {
	capstanAcceleration=0.0;
	capstanSpeed=-REWINDSPEED;
	status=REWIND_KEEP;
      }
      break;
    case REWIND_KEEP:
      if(OUTlength<GAPLEN)
      {
	capstanAcceleration=CAPSTANACCELERATION;
	status=REWIND_DECELERATE;
      }
      break;
    case REWIND_DECELERATE:
      if(capstanSpeed>-0.01)
      {
	capstanSpeed=0;
	capstanAcceleration=0;
	OUTlength=0.0;
	INlength=TAPELENGTH;
	taperead=0;
	status=TAPE_IDLE;
      }
      break;
  }
  INlength -= inSpeed*dsecs;
  OUTlength -= outSpeed*dsecs;
  inTape += inSpeed*dsecs;
  outTape += outSpeed*dsecs;
  inTape -= capstanSpeed*dsecs;
  outTape += capstanSpeed*dsecs;
  taperead += capstanSpeed*dsecs;
  inSpeed += inAcceleration*dsecs;
  outSpeed += outAcceleration*dsecs;
  capstanSpeed += capstanAcceleration*dsecs;
  
  inRatio = inTape/MAXCHAMPERTAPELENGTH - 0.5;
  outRatio = outTape/MAXCHAMPERTAPELENGTH - 0.5;

  inError=inSpeed-capstanSpeed;
  outError=outSpeed+capstanSpeed;
  inAcceleration= -inError*UAKK;
  if(fabs(inRatio)>0.2)inAcceleration-=inRatio*UAKK;
  outAcceleration= -outError*UAKK;
  if(fabs(outRatio)>0.2)outAcceleration-=outRatio*UAKK;
  total=INlength+OUTlength+inTape+outTape;

//printf("secs: %.3f status: %d\n\tINlength: %.2f inTape: %.2f inSpeed: %.3f inAcceleration: %.3f inRatio: %.3f\n\tcapstanSpeed: %.3f capstanAcceleration: %.3f\n\tOUTlength: %.2f outTape: %.2f outSpeed: %.3f outAcceleration: %.3f outRatio: %.3f\n",secs,status,INlength,inTape,inSpeed, inAcceleration,inRatio,capstanSpeed,capstanAcceleration,OUTlength,outTape,outSpeed,outAcceleration,outRatio);
//printf("secs: %.3f dsecs: %.6f INlength: %.8f OUTlength: %.8f inRatio: %.3f outRatio: %.3f taperead: %.8f total: %.8f\n",secs,dsecs,INlength,OUTlength,inRatio,outRatio,taperead,total);

  if(inRatio < -0.5 || inRatio > 0.5 || outRatio < -0.5 || outRatio > 0.5)
  {
    printf("inRatio: %g outRatio: %g\n",inRatio,outRatio);
  }
}

static int textwidth(char *t)
{
  int w;
  char *p=t;
  w=0;
  while(*p)
  {
    w += glutStrokeWidth(GLUT_STROKE_ROMAN, (int) *p);
    p++;
  }
  return(w);
}

GLvoid DrawGLScene(GLvoid)
{
  char txt[100];
  double x,y;
  int width, height;
  int widthr, heightr;
  GLdouble window_xmin, window_xmax, window_ymin, window_ymax;
  GLdouble xcenter, ycenter, aspect, xsize, ysize, fHeight, fWidth;
  double a1,c1,xi1,yi1,xi2,yi2,angle1,angle2;
  double xi11,yi11,xi12,yi12,xi21,yi21,xi22,yi22;
  double xcenter1,ycenter1,xcenter2,ycenter2,acenter,ccenter;
  double r1,angle3,x1,y1,x2,y2,x3,y3,s,sx,sy;
  double tapewidth=1.0;
  double textXmin,textXmax,textYmin,textYmax;

  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  glLoadIdentity();
//glViewport(0, 0, window_width, window_height);
  glOrtho(0.0,((double)XMAX)*window_aspect,((double)YMAX),0.0,-1.0,1.0);
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glLoadIdentity();

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		// Clear The Screen And The Depth Buffer
  glDisable(GL_BLEND);
  glDisable(GL_TEXTURE_2D);
  glLoadIdentity();				// Reset The View
  glBegin(GL_LINES);
  glColor4d(0.0,0.0,0.0,1.0);
  glLineWidth(7.0);
  /*
  glVertex3d(BottomReelX-BottomReelOuterR,BottomReelY-BottomReelOuterR,0.0);
  glVertex3d(BottomReelX-BottomReelOuterR,BottomReelY+BottomReelOuterR,0.0);

  glVertex3d(BottomReelX-BottomReelOuterR,BottomReelY+BottomReelOuterR,0.0);
  glVertex3d(BottomReelX+BottomReelOuterR,BottomReelY+BottomReelOuterR,0.0);

  glVertex3d(BottomReelX+BottomReelOuterR,BottomReelY+BottomReelOuterR,0.0);
  glVertex3d(BottomReelX+BottomReelOuterR,BottomReelY-BottomReelOuterR,0.0);

  glVertex3d(BottomReelX+BottomReelOuterR,BottomReelY-BottomReelOuterR,0.0);
  glVertex3d(BottomReelX-BottomReelOuterR,BottomReelY-BottomReelOuterR,0.0);
  */

  circle(TopReelX, TopReelY, TopReelOuterR, 0.0, 360.0);
  circle(TopReelX, TopReelY, TopReelInnerR, 0.0, 360.0);

#ifdef USECORNER
  circle(TopCornerX, TopCornerY, TopCornerOuterR, 0.0, 360.0);
  circle(TopCornerX, TopCornerY, TopCornerInnerR, 0.0, 360.0);
#endif

  circle(TopChamperInX, TopChamperInY, TopChamperInInnerR, 0.0, 360.0);

  points2Line(TopChamperOuter1X, TopChamperOuter1Y, TopChamperOuter2X, TopChamperOuter2Y,
              &a1, &c1);
  intersectionLineCircle(a1,c1,TopChamperInX,TopChamperInY,TopChamperInInnerR,
              &xi1,&yi1,&xi2,&yi2);

  glVertex3d(xi2,yi2,0.0);
  glVertex3d(TopChamperOuter2X,TopChamperOuter2Y,0.0);

  intersectionLineCircle(a1,c1,TopChamperInX,TopChamperInY,TopChamperInOuterR,
              &xi1,&yi1,&xi2,&yi2);

  angle1=-atan2(yi2-TopChamperInY,xi2-TopChamperInX)*180.0/M_PI;
  points2Line(TopChamperOuter4X, TopChamperOuter4Y, TopChamperOuter1X, TopChamperOuter1Y,
              &a1,&c1);
  intersectionLineCircle(a1,c1,TopChamperInX,TopChamperInY,TopChamperInOuterR,
              &xi1,&yi1,&xi2,&yi2);
  angle2=360.0-atan2(yi2-TopChamperInY,xi2-TopChamperInX)*180.0/M_PI;

//printf("Top: angle1: %lg angle2: %lg\n",angle1,angle2);

  circle(TopChamperInX, TopChamperInY, TopChamperInOuterR, angle1, angle2);

  glVertex3d(TopChamperOuter2X,TopChamperOuter2Y,0.0);
  glVertex3d(TopChamperOuter3X,TopChamperOuter3Y,0.0);

  glVertex3d(TopChamperOuter3X,TopChamperOuter3Y,0.0);
  glVertex3d(TopChamperOuter4X,TopChamperOuter4Y,0.0);

  glVertex3d(TopChamperOuter4X,TopChamperOuter4Y,0.0);
  glVertex3d(TopChamperOuter1X,TopChamperOuter1Y,0.0);

  glVertex3d(TopChamperOuter1X+9.0,TopChamperOuter1Y+7.0,0.0);
  glVertex3d(735.0,37.0,0.0);

  glVertex3d(TopChamperInner2X, TopChamperInner2Y, 0.0);
  glVertex3d(TopChamperInner3X, TopChamperInner3Y, 0.0);

  points2Line(799.0,88.0,TopChamperInner4X,TopChamperInner4Y,&a1,&c1);
  intersectionLineCircle(a1,c1,TopChamperOutX,TopChamperOutY,TopChamperOutR,
                         &xi1,&yi1,&xi2,&yi2);
  glVertex3d(799.0,88.0,0.0);
  glVertex3d(xi2,yi2,0.0);
  circle(TopChamperOutX,TopChamperOutY,TopChamperOutR,0.0,360.0);

  glVertex3d(Head1X,Head1Y,0.0);
  glVertex3d(Head2X,Head2Y,0.0);

  glVertex3d(Head2X,Head2Y,0.0);
  glVertex3d(Head3X,Head3Y,0.0);

  glVertex3d(Head3X,Head3Y,0.0);
  glVertex3d(Head4X,Head4Y,0.0);

  glVertex3d(Head4X,Head4Y,0.0);
  glVertex3d(Head5X,Head5Y,0.0);

  glVertex3d(Head5X,Head5Y,0.0);
  glVertex3d(Head6X,Head6Y,0.0);

  glVertex3d(Head6X,Head6Y,0.0);
  glVertex3d(Head1X,Head1Y,0.0);

  circle(CapstanX,CapstanY,CapstanR,0.0,360.0);

#ifdef USECORNER
  circle(BottomCornerX, BottomCornerY, BottomCornerOuterR, 0.0, 360.0);
  circle(BottomCornerX, BottomCornerY, BottomCornerInnerR, 0.0, 360.0);
#endif

  circle(BottomChamperInX, BottomChamperInY, BottomChamperInInnerR, 0.0, 360.0);

  points2Line(BottomChamperOuter1X, BottomChamperOuter1Y, BottomChamperOuter2X, BottomChamperOuter2Y,
              &a1, &c1);
  intersectionLineCircle(a1,c1,BottomChamperInX,BottomChamperInY,BottomChamperInInnerR,
              &xi1,&yi1,&xi2,&yi2);

  glVertex3d(xi2,yi2,0.0);
  glVertex3d(BottomChamperOuter2X,BottomChamperOuter2Y,0.0);

  intersectionLineCircle(a1,c1,BottomChamperInX,BottomChamperInY,BottomChamperInOuterR,
              &xi1,&yi1,&xi2,&yi2);

  angle1=-atan2(yi2-BottomChamperInY,xi2-BottomChamperInX)*180.0/M_PI;
  points2Line(BottomChamperOuter4X, BottomChamperOuter4Y, BottomChamperOuter1X, BottomChamperOuter1Y,
              &a1,&c1);
  intersectionLineCircle(a1,c1,BottomChamperInX,BottomChamperInY,BottomChamperInOuterR,
              &xi1,&yi1,&xi2,&yi2);
  angle2=360+atan2(yi2-BottomChamperInY,xi2-BottomChamperInX)*180.0/M_PI;

//printf("Bottom: angle1: %lg angle2: %lg\n",angle1,angle2);
  circle(BottomChamperInX, BottomChamperInY, BottomChamperInOuterR, -angle2, angle1);

  glVertex3d(BottomChamperOuter2X,BottomChamperOuter2Y,0.0);
  glVertex3d(BottomChamperOuter3X,BottomChamperOuter3Y,0.0);

  glVertex3d(BottomChamperOuter3X,BottomChamperOuter3Y,0.0);
  glVertex3d(BottomChamperOuter4X,BottomChamperOuter4Y,0.0);

  glVertex3d(BottomChamperOuter4X,BottomChamperOuter4Y,0.0);
  glVertex3d(BottomChamperOuter1X,BottomChamperOuter1Y,0.0);

  glVertex3d(BottomChamperOuter1X+9.0,BottomChamperOuter1Y-7.0,0.0);
  glVertex3d(735.0,MirrorY-37.0,0.0);

  glVertex3d(BottomChamperInner2X, BottomChamperInner2Y, 0.0);
  glVertex3d(BottomChamperInner3X, BottomChamperInner3Y, 0.0);

  points2Line(799.0,MirrorY-88.0,BottomChamperInner4X,BottomChamperInner4Y,&a1,&c1);
  intersectionLineCircle(a1,c1,BottomChamperOutX,BottomChamperOutY,BottomChamperOutR,
                         &xi1,&yi1,&xi2,&yi2);
  glVertex3d(799.0,MirrorY-88.0,0.0);
  glVertex3d(xi2,yi2,0.0);
  circle(BottomChamperOutX,BottomChamperOutY,BottomChamperOutR,0.0,360.0);

  // Tape:

  glEnd();
  glColor4d(150.0/255.0,75.0/255.0,0.0,1.0);
  glBegin(GL_TRIANGLES);
  inRadius=length2Radius(INlength)*PIXELSPERM;
  inRotation=-fmod(length2Rotation(INlength)*360.0,360.0);
  outRadius=length2Radius(OUTlength)*PIXELSPERM;
//printf("inRadius: %g outRadius: %g\n",inRadius,outRadius);
  outRotation=fmod(length2Rotation(OUTlength)*360.0,360.0);
  disk(TopReelX,TopReelY,0.0,TopReelInnerR,inRadius);
  disk(BottomReelX,BottomReelY, 0.5,BottomReelInnerR,outRadius);
  glEnd();
  glBegin(GL_LINES);

#ifdef USECORNER
  twoCirclesTangent(TopReelX,TopReelY,inRadius,
                    TopCornerX,TopCornerY,TopCornerInnerR,0,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi11,yi11,0.0);
  glVertex3d(xi21,yi21,0.0);

  twoCirclesTangent(TopCornerX,TopCornerY,TopCornerInnerR,
                    TopChamperInX,TopChamperInY,TopChamperInInnerR,1,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi12,yi12,0.0);
  glVertex3d(xi21,yi21,0.0);
#else
  twoCirclesTangent(TopReelX,TopReelY,inRadius,
                    TopChamperInX,TopChamperInY,TopChamperInInnerR,1,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi12,yi12,0.0);
  glVertex3d(xi21,yi21,0.0);
#endif

  xcenter1=(TopChamperInner1X+TopChamperInner4X)/2.0;
  ycenter1=(TopChamperInner1Y+TopChamperInner4Y)/2.0;
  xcenter2=(TopChamperInner2X+TopChamperInner3X)/2.0;
  ycenter2=(TopChamperInner2Y+TopChamperInner3Y)/2.0;
  points2Line(xcenter1,ycenter1,xcenter2,ycenter2,&acenter,&ccenter);
  x=xcenter1+(xcenter2-xcenter1)*(inRatio+0.5);
  y=-ccenter-acenter*x;
  r1=fabs(acenter*TopChamperInner1X+TopChamperInner1Y+ccenter)/sqrt(SQR(acenter)+1.0)-tapewidth*0.5;
  angle3=atan(acenter)*180.0/M_PI;
//printf("angle3: %g\n",angle3);
//glVertex3d(xcenter1,-ccenter-acenter*xcenter1,0.0);
//glVertex3d(xcenter2,-ccenter-acenter*xcenter2,0.0);
  circle(x,y,r1,angle3-90.0,angle3+90.0);

  x2=r1*cos((angle3+90.0)/180.0*M_PI)+x;
  y2=r1*sin((angle3-90.0)/180.0*M_PI)+y;

  x3=xcenter1+5.0;
  y3=-ccenter-acenter*x3;
  x1=r1*cos((angle3+90.0)/180.0*M_PI)+x3;
  y1=r1*sin((angle3-90.0)/180.0*M_PI)+y3;
  glVertex3d(x1,y1,0.0);
  glVertex3d(x2,y2,0.0);

  x2=r1*cos((angle3-90.0)/180.0*M_PI)+x;
  y2=r1*sin((angle3-270.0)/180.0*M_PI)+y;
  
  x3=xcenter1+15.0;
  y3=-ccenter-acenter*x3;
  x1=r1*cos((angle3-90.0)/180.0*M_PI)+x3;
  y1=r1*sin((angle3-270.0)/180.0*M_PI)+y3;
  glVertex3d(x1,y1,0.0);
  glVertex3d(x2,y2,0.0);

  twoCirclesTangent(TopChamperOutX,TopChamperOutY,TopChamperOutR,
                    Head3X,Head3Y,tapewidth*0.5,1,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi12,yi12,0.0);
  glVertex3d(xi21,yi21,0.0);
  x=xi21+Head4X-Head3X;
  y=yi21;
  glVertex3d(xi21,yi21,0.0);
  glVertex3d(x,y,0.0);
  
  twoCirclesTangent(Head4X,Head4Y,tapewidth*0.5,
                    CapstanX,CapstanY,CapstanR,0,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(x,y,0.0);
  glVertex3d(xi22,yi22,0.0);

  twoCirclesTangent(CapstanX,CapstanY,CapstanR,
                    BottomChamperOutX,BottomChamperOutY,BottomChamperOutR,1,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi12,yi12,0.0);
  glVertex3d(xi21,yi21,0.0);

  xcenter1=(BottomChamperInner1X+BottomChamperInner4X)/2.0;
  ycenter1=(BottomChamperInner1Y+BottomChamperInner4Y)/2.0;
  xcenter2=(BottomChamperInner2X+BottomChamperInner3X)/2.0;
  ycenter2=(BottomChamperInner2Y+BottomChamperInner3Y)/2.0;
  points2Line(xcenter1,ycenter1,xcenter2,ycenter2,&acenter,&ccenter);
  x=xcenter1+(xcenter2-xcenter1)*(outRatio+0.5);
  y=-ccenter-acenter*x;
  r1=fabs(acenter*BottomChamperInner1X+BottomChamperInner1Y+ccenter)/
     sqrt(SQR(acenter)+1.0)-tapewidth*0.5;
  angle3=atan(acenter)*180.0/M_PI;
  circle(x,y,r1,angle3-90.0,angle3+90.0);

  x2=r1*cos((angle3+90.0)/180.0*M_PI)+x;
  y2=r1*sin((angle3-90.0)/180.0*M_PI)+y;
  x3=xcenter1+15;
  y3=-ccenter-acenter*x3;
  x1=r1*cos((angle3+90.0)/180.0*M_PI)+x3;
  y1=r1*sin((angle3-90.0)/180.0*M_PI)+y3;
  glVertex3d(x1,y1,0.0);
  glVertex3d(x2,y2,0.0);

  x2=r1*cos((angle3-90.0)/180.0*M_PI)+x;
  y2=r1*sin((angle3-270.0)/180.0*M_PI)+y;
  x3=xcenter1+5.0;
  y3=-ccenter-acenter*x3;
  x1=r1*cos((angle3-90.0)/180.0*M_PI)+x3;
  y1=r1*sin((angle3-270.0)/180.0*M_PI)+y3;
  glVertex3d(x1,y1,0.0);
  glVertex3d(x2,y2,0.0);

#ifdef USECORNER
  twoCirclesTangent(BottomReelX,BottomReelY,outRadius,
                    BottomCornerX,BottomCornerY,BottomCornerInnerR,0,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi11,yi11,0.0);
  glVertex3d(xi21,yi21,0.0);

  twoCirclesTangent(BottomCornerX,BottomCornerY,BottomCornerInnerR,
                    BottomChamperInX,BottomChamperInY,BottomChamperInInnerR,1,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi12,yi12,0.0);
  glVertex3d(xi21,yi21,0.0);
#else
  twoCirclesTangent(BottomReelX,BottomReelY,outRadius,
                    BottomChamperInX,BottomChamperInY,BottomChamperInInnerR,1,
		    &xi11,&yi11,&xi12,&yi12,&xi21,&yi21,&xi22,&yi22);
  glVertex3d(xi12,yi12,0.0);
  glVertex3d(xi21,yi21,0.0);
#endif


  glEnd();

// Label on top reel:
//#define TopReelLabelWidth 100.0
//#define TopReelLabelHeight 50.0
//#define TopReelLabelDistance 100.0

// kilroy
  glPushMatrix();
  glTranslated(TopReelX,TopReelY,0.0);
  glRotated(inRotation,0.0,0.0,1.0);
  glPolygonMode(GL_FRONT, GL_FILL);
  glPolygonMode(GL_BACK, GL_FILL);
  glBegin(GL_QUADS);
    glColor4d(0.8,0.8,0.8,0.0);
    glVertex3d(-TopReelLabelWidth/2.0, TopReelLabelDistance+TopReelLabelHeight/2.0, 0.5);
    glVertex3d( TopReelLabelWidth/2.0, TopReelLabelDistance+TopReelLabelHeight/2.0, 0.5);
    glVertex3d( TopReelLabelWidth/2.0, TopReelLabelDistance-TopReelLabelHeight/2.0, 0.5);
    glVertex3d(-TopReelLabelWidth/2.0, TopReelLabelDistance-TopReelLabelHeight/2.0, 0.5);
  glEnd();
  glColor4d(0.0,0.0,0.0,0.0);
//glTranslated(-TopReelLabelWidth/2.0, TopReelLabelDistance+TopReelLabelHeight/2.0, 1.0);
  glTranslated(0.0, TopReelLabelDistance, 1.0);
  bbox(1.0, &textXmin, &textXmax, &textYmin, &textYmax, LABELTEXT);
  printf("textXmin: %g textXmax: %g textYmin: %g textYmax: %g\n",
      textXmin, textXmax, textYmin, textYmax);
  sx=TopReelLabelWidth/(textXmax-textXmin);
  sy=TopReelLabelHeight/(textYmax-textYmin);
  s=sx;
  if(s>sy) s=sy;
  printf("sx: %g sy: %g s: %g\n",sx,sy,s);
  glScaled(s,-s,1.0);
  glTranslated(-(textXmin+textXmax)*0.5, -(textYmin+textYmax)*0.5, 0.0);
  glBegin(GL_LINES);
  stroke(1.0, 0.0, 0.0, 0.0, LABELTEXT);
  glEnd();
  glPopMatrix();
  
  glEnable(GL_BLEND);
  glPushMatrix();
  glTranslated(BottomReelX-BottomReelOuterR,BottomReelY-BottomReelOuterR,0.0);
  glScaled(BottomReelOuterR*2.0,BottomReelOuterR*2.0,1.0);
  glTranslated(0.5,0.5,0.0);
  glRotated(outRotation,0.0,0.0,1.0);
  glTranslated(-0.5,-0.5,0.0);
  
  glEnable(GL_TEXTURE_2D);			// Enable Texture Mapping
  glBindTexture(GL_TEXTURE_2D, texture[0]);   // choose the texture to use.


  glBegin(GL_QUADS);
    glColor4d(1.0,1.0,1.0,1.0);
    glTexCoord2d(0.0, 0.0);
    glVertex3d(0.0, 0.0, 1.0);
    glTexCoord2d(0.0, 1.0);
    glVertex3d(0.0, 1.0, 1.0);
    glTexCoord2d(1.0, 1.0);
    glVertex3d(1.0, 1.0, 1.0);
    glTexCoord2d(1.0, 0.0);
    glVertex3d(1.0, 0.0, 1.0);

  glEnd();
  glPopMatrix();
 




  // since this is double buffered, swap the buffers to display what just got drawn.
  glutSwapBuffers();

}
static void command(int cmd)
{
  switch(cmd)
  {
    case TAPE_REWIND:
      if(taperead>0)
      {
	capstanAcceleration=-CAPSTANACCELERATION;
	UAKK=22;
	status=REWIND_ACCELERATE;
      }
      break;
    case TAPE_FORWARD:
      readstart=taperead;
      capstanAcceleration=CAPSTANACCELERATION;
      UAKK=4;
      status=FORWARD_ACCELERATE;
      break;
    case TAPE_REVERSE:
      if(taperead>0)
      {
	readstart=taperead;
	capstanAcceleration=-CAPSTANACCELERATION;
	UAKK=4;
	status=REVERSE_ACCELERATE;
      }
      break;
  }
}

void keyPressed(unsigned char key, int x, int y) 
{
  printf("key: %d\n", key);
  switch (key)
  {    
    case '\e':
    case 'q':
    case 'Q':
      exit(1);                   	
      break;
    case 'r':
    case 'R':
      if(status!=0) return;
      tapeappetite=BLOCKLEN;
      command(TAPE_REWIND);
      TapeUpdate();
      glutSetWindow(window);
      glutPostRedisplay();
      break;
    case ' ':
    case 'f':
    case 'F':
//    if(status!=0) return;
      tapeappetite=BLOCKLEN;
      command(TAPE_FORWARD);
      TapeUpdate();
      glutSetWindow(window);
      glutPostRedisplay();
      break;
    case 'b':
    case 'B':
      if(status!=0) return;
      command(TAPE_REVERSE);
      TapeUpdate();
      glutSetWindow(window);
      glutPostRedisplay();
      break;
    default:
      // printf ("Key %d pressed. No action there yet.\n", key);
      break;
  }	
  DrawGLScene();
}

void specialKeyPressed(int key, int x, int y) 
{
  int width, height;
  width=xmax-xmin+1;
  height=ymax-ymin+1;

  printf("key: %d\n",key);

  switch (key)
  {    
    case GLUT_KEY_PAGE_UP:
      break;
    case GLUT_KEY_PAGE_DOWN:
      break;
    case GLUT_KEY_UP:
      break;
    case GLUT_KEY_DOWN:
      break;
    case GLUT_KEY_LEFT:
      break;
    case GLUT_KEY_RIGHT:
      break;
    case GLUT_KEY_HOME:
      command(TAPE_REWIND);
      TapeUpdate();
      glutSetWindow(window);
      glutPostRedisplay();
      break;
    case GLUT_KEY_END:
      tapeappetite=INlength-1.0;
      command(TAPE_FORWARD);
      TapeUpdate();
      glutSetWindow(window);
      glutPostRedisplay();
      break;

    default:
	// printf ("Special key %d pressed. No action there yet.\n", key);
	break;
  }	
  DrawGLScene();
}

void mouseFunc(int button, int state, int x, int y)
{
  int width, height;
  int picturex, picturey;
  double distance;
  /*
  	button:

        0: Left
        1: Middle
        2: Right
        3: Wheel up
        4: Wheel down
  */
}


static void idle()
{
  TapeUpdate();
  glutSetWindow(window);
  glutPostRedisplay();
}

int main(int argc, char **argv)
{
  int i;
  
  clock_gettime(CLOCK_MONOTONIC, &time0);
  lastsecs=0.0;
  glutInit(&argc, argv);
//UAKK=strtod(argv[1], NULL);
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
  glutInitWindowSize(wXMAX, wYMAX);
  glutInitWindowPosition(0, 0);
  window = glutCreateWindow("ampex2");

  glutDisplayFunc(&DrawGLScene);
  /* glutFullScreen(); */

  glutIdleFunc(&idle);
  glutReshapeFunc(&ReSizeGLScene);
  glutKeyboardFunc(&keyPressed);
  glutSpecialFunc(&specialKeyPressed);
  glutMouseFunc(&mouseFunc);
  InitGL(wXMAX, wYMAX);
  glutMainLoop();

  return 1;
}

