| 
							- /*
 -  * fractviewer.cxx [from agviewer.c  (version 1.0)]
 -  *
 -  * AGV: a glut viewer. Routines for viewing a 3d scene w/ glut
 -  *
 -  * See agv_example.c and agviewer.h comments within for more info.
 -  *
 -  * I welcome any feedback or improved versions!
 -  *
 -  * Philip Winston - 4/11/95
 -  * pwinston@hmc.edu
 -  * http://www.cs.hmc.edu/people/pwinston
 -  */
 - 
 - #include <config.h>
 - 
 - #if HAVE_GL && HAVE_GL_GLU_H
 - #  include <FL/glut.H>
 - #  include <FL/glu.h>
 - 
 - #  include <stdio.h>
 - #  include <stdlib.h>
 - #  include <math.h>
 - #  include <sys/types.h>
 - #  include <time.h>
 - #  if !defined(WIN32) && !defined(__EMX__)
 - #    include <sys/time.h>
 - #  endif // !WIN32 && !__EMX__
 - 
 - #  include "fracviewer.h"
 - 
 - /* Some <math.h> files do not define M_PI... */
 - #ifndef M_PI
 - #define M_PI 3.14159265
 - #endif
 - 
 - /***************************************************************/
 - /************************** SETTINGS ***************************/
 - /***************************************************************/
 - 
 -    /* Initial polar movement settings */
 - #define INIT_POLAR_AZ  0.0
 - #define INIT_POLAR_EL 30.0
 - #define INIT_DIST      4.0
 - #define INIT_AZ_SPIN   0.5
 - #define INIT_EL_SPIN   0.0
 - 
 -   /* Initial flying movement settings */
 - #define INIT_EX        0.0
 - #define INIT_EY       -2.0
 - #define INIT_EZ       -2.0
 - #define INIT_MOVE     0.01
 - #define MINMOVE      0.001    
 - 
 -   /* Start in this mode */
 - #define INIT_MODE   POLAR   
 - 
 -   /* Controls:  */
 - 
 -   /* map 0-9 to an EyeMove value when number key is hit in FLYING mode */
 - #define SPEEDFUNCTION(x) ((x)*(x)*0.001)  
 - 
 -   /* Multiply EyeMove by (1+-MOVEFRACTION) when +/- hit in FLYING mode */
 - #define MOVEFRACTION 0.25   
 - 
 -   /* What to multiply number of pixels mouse moved by to get rotation amount */
 - #define EL_SENS   0.5
 - #define AZ_SENS   0.5
 - 
 -   /* What to multiply number of pixels mouse moved by for movement amounts */
 - #define DIST_SENS 0.01
 - #define E_SENS    0.01
 - 
 -   /* Minimum spin to allow in polar (lower forced to zero) */
 - #define MIN_AZSPIN 0.1
 - #define MIN_ELSPIN 0.1
 - 
 -   /* Factors used in computing dAz and dEl (which determine AzSpin, ElSpin) */
 - #define SLOW_DAZ 0.90
 - #define SLOW_DEL 0.90
 - #define PREV_DAZ 0.80
 - #define PREV_DEL 0.80
 - #define CUR_DAZ  0.20
 - #define CUR_DEL  0.20
 - 
 - /***************************************************************/
 - /************************** GLOBALS ****************************/
 - /***************************************************************/
 - 
 - int     MoveMode = INIT_MODE;  /* FLYING or POLAR mode? */
 - 
 - GLfloat Ex = INIT_EX,             /* flying parameters */
 -         Ey = INIT_EY,
 -         Ez = INIT_EZ,
 -         EyeMove = INIT_MOVE,     
 - 
 -         EyeDist = INIT_DIST,      /* polar params */
 -         AzSpin  = INIT_AZ_SPIN,
 -         ElSpin  = INIT_EL_SPIN,
 - 
 -         EyeAz = INIT_POLAR_AZ,    /* used by both */
 -         EyeEl = INIT_POLAR_EL;
 - 
 - int agvMoving;    /* Currently moving?  */
 - 
 - int downx, downy,   /* for tracking mouse position */
 -     lastx, lasty,
 -     downb = -1;     /* and button status */
 - 						
 - GLfloat downDist, downEl, downAz, /* for saving state of things */
 -         downEx, downEy, downEz,   /* when button is pressed */
 -         downEyeMove;                
 - 
 - GLfloat dAz, dEl, lastAz, lastEl;  /* to calculate spinning w/ polar motion */
 - int     AdjustingAzEl = 0;
 - 
 - int AllowIdle, RedisplayWindow; 
 -    /* If AllowIdle is 1 it means AGV will install its own idle which
 -     * will update the viewpoint as needed and send glutPostRedisplay() to the
 -     * window RedisplayWindow which was set in agvInit().  AllowIdle of 0
 -     * means AGV won't install an idle funciton, and something like
 -     * "if (agvMoving) agvMove()" should exist at the end of the running
 -     * idle function.
 -     */
 - 
 - #define MAX(x,y) (((x) > (y)) ? (x) : (y))
 - #define TORAD(x) ((M_PI/180.0)*(x))
 - #define TODEG(x) ((180.0/M_PI)*(x))
 - 
 - /***************************************************************/
 - /************************ PROTOTYPES ***************************/
 - /***************************************************************/
 - 
 -   /*
 -    * these are functions meant for internal use only
 -    * the other prototypes are in agviewer.h
 -    */
 - 
 - void PolarLookFrom(GLfloat dist, GLfloat elevation, GLfloat azimuth);
 - void FlyLookFrom(GLfloat x, GLfloat y, GLfloat z,
 -                         GLfloat az, GLfloat el);
 - int  ConstrainEl(void);
 - void MoveOn(int v);
 - void SetMove(float newmove);
 - static void normalize(GLfloat v[3]);
 - void ncrossprod(float v1[3], float v2[3], float cp[3]);
 - 
 - 
 - /***************************************************************/
 - /************************ agvInit ******************************/
 - /***************************************************************/
 - 
 - void agvInit(int window)
 - {
 -   glutMouseFunc(agvHandleButton);
 -   glutMotionFunc(agvHandleMotion);
 -   glutKeyboardFunc(agvHandleKeys);
 -   RedisplayWindow = glutGetWindow();
 -   agvSetAllowIdle(window);
 - }
 - 
 - /***************************************************************/
 - /************************ VIEWPOINT STUFF **********************/
 - /***************************************************************/
 - 
 -   /*
 -    * viewing transformation modified from page 90 of red book
 -    */
 - void PolarLookFrom(GLfloat dist, GLfloat elevation, GLfloat azimuth)
 - {
 -   glTranslatef(0, 0, -dist);
 -   glRotatef(elevation, 1, 0, 0);
 -   glRotatef(azimuth, 0, 1, 0);
 - 
 - }
 - 
 -   /*
 -    * I took the idea of tracking eye position in absolute
 -    * coords and direction looking in Polar form from denis
 -    */
 - void FlyLookFrom(GLfloat x, GLfloat y, GLfloat z, GLfloat az, GLfloat el)
 - {
 -   float lookat[3], perp[3], up[3];
 - 
 -   lookat[0] = sin(TORAD(az))*cos(TORAD(el));
 -   lookat[1] = sin(TORAD(el));
 -   lookat[2] = -cos(TORAD(az))*cos(TORAD(el));
 -   normalize(lookat);
 -   perp[0] = lookat[2];
 -   perp[1] = 0;
 -   perp[2] = -lookat[0];
 -   normalize(perp);
 -   ncrossprod(lookat, perp, up);
 -   gluLookAt(x, y, z,
 -             x+lookat[0], y+lookat[1], z+lookat[2],
 -             up[0], up[1], up[2]);
 - }
 - 
 -   /*
 -    * Call viewing transformation based on movement mode
 -    */
 - void agvViewTransform(void)
 - { 
 -   switch (MoveMode) {
 -     case FLYING:
 -       FlyLookFrom(Ex, Ey, Ez, EyeAz, EyeEl);
 -       break;
 -     case POLAR:
 -       PolarLookFrom(EyeDist, EyeEl, EyeAz);
 -       break;
 -     }
 - }
 - 
 -   /*
 -    * keep them vertical; I think this makes a lot of things easier, 
 -    * but maybe it wouldn't be too hard to adapt things to let you go
 -    * upside down
 -    */
 - int ConstrainEl(void)
 - {
 -   if (EyeEl <= -90) {
 -     EyeEl = -89.99;
 -     return 1;
 -   } else if (EyeEl >= 90) {
 -     EyeEl = 89.99;
 -     return 1;
 -   }
 -   return 0;
 - }
 - 
 -  /*
 -   * Idle Function - moves eyeposition
 -   */
 - void agvMove(void)
 - {
 -   switch (MoveMode)  {
 -     case FLYING:
 -       Ex += EyeMove*sin(TORAD(EyeAz))*cos(TORAD(EyeEl));
 -       Ey += EyeMove*sin(TORAD(EyeEl));
 -       Ez -= EyeMove*cos(TORAD(EyeAz))*cos(TORAD(EyeEl));
 -       break;
 - 
 -     case POLAR:
 -       EyeEl += ElSpin;
 -       EyeAz += AzSpin;
 -       if (ConstrainEl()) {  /* weird spin thing to make things look     */
 -         ElSpin = -ElSpin;      /* look better when you are kept from going */
 -                                /* upside down while spinning - Isn't great */
 -         if (fabs(ElSpin) > fabs(AzSpin))
 -           AzSpin = fabs(ElSpin) * ((AzSpin > 0) ? 1 : -1);
 -       }
 -       break;
 -     }
 - 
 -   if (AdjustingAzEl) {
 -     dAz *= SLOW_DAZ;
 -     dEl *= SLOW_DEL;
 -   }
 - 
 -   if (AllowIdle) {
 -     glutSetWindow(RedisplayWindow);
 -     glutPostRedisplay();
 -   }
 - }
 - 
 - 
 -   /*
 -    * Don't install agvMove as idle unless we will be updating the view
 -    * and we've been given a RedisplayWindow
 -    */
 - void MoveOn(int v)
 - {
 -   if (v && ((MoveMode == FLYING && EyeMove != 0) ||
 -              (MoveMode == POLAR &&
 -              (AzSpin != 0 || ElSpin != 0 || AdjustingAzEl)))) {
 -     agvMoving = 1;
 -     if (AllowIdle)
 -       glutIdleFunc(agvMove);
 -   } else {
 -     agvMoving = 0;
 -     if (AllowIdle)
 -       glutIdleFunc(NULL);
 -   }
 - }
 - 
 -   /*
 -    * set new redisplay window.  If <= 0 it means we are not to install
 -    * an idle function and will rely on whoever does install one to 
 -    * put statement like "if (agvMoving) agvMove();" at end of it
 -    */
 - void agvSetAllowIdle(int allowidle)
 - {
 -   if ((AllowIdle = allowidle))
 -     MoveOn(1);
 - }
 - 
 - 
 -   /*
 -    * when moving to flying we stay in the same spot, moving to polar we
 -    * reset since we have to be looking at the origin (though a pivot from
 -    * current position to look at origin might be cooler)
 -    */
 - void agvSwitchMoveMode(int move)
 - {
 -   switch (move) {
 -     case FLYING:
 -       if (MoveMode == FLYING) return;
 -       Ex    = -EyeDist*sin(TORAD(EyeAz))*cos(TORAD(EyeEl));
 -       Ey    =  EyeDist*sin(TORAD(EyeEl));
 -       Ez    =  EyeDist*(cos(TORAD(EyeAz))*cos(TORAD(EyeEl)));
 -       EyeAz =  EyeAz;
 -       EyeEl = -EyeEl;
 -       EyeMove = INIT_MOVE;
 -       break;
 -     case POLAR:
 -       EyeDist = INIT_DIST;
 -       EyeAz   = INIT_POLAR_AZ;
 -       EyeEl   = INIT_POLAR_EL;
 -       AzSpin  = INIT_AZ_SPIN;
 -       ElSpin  = INIT_EL_SPIN;
 -       break;
 -     }
 -   MoveMode = move;
 -   MoveOn(1);
 -   glutPostRedisplay();
 - }
 - 
 - /***************************************************************/
 - /*******************    MOUSE HANDLING   ***********************/
 - /***************************************************************/
 - 
 - void agvHandleButton(int button, int state, int x, int y)
 - {
 -  if (state == GLUT_DOWN && downb == -1) {  
 -     lastx = downx = x;
 -     lasty = downy = y;
 -     downb = button;    
 - 
 -     switch (button) {
 -       case GLUT_LEFT_BUTTON:
 -         lastEl = downEl = EyeEl;
 -         lastAz = downAz = EyeAz;
 -         AzSpin = ElSpin = dAz = dEl = 0;
 -         AdjustingAzEl = 1;
 - 	MoveOn(1);
 -         break;
 - 
 -       case GLUT_MIDDLE_BUTTON:
 -         downDist = EyeDist;
 - 	downEx = Ex;
 - 	downEy = Ey;
 - 	downEz = Ez;
 - 	downEyeMove = EyeMove;
 - 	EyeMove = 0;
 -     }
 - 
 -   } else if (state == GLUT_UP && button == downb) {
 - 
 -     downb = -1;
 - 
 -     switch (button) {
 -       case GLUT_LEFT_BUTTON:
 -         if (MoveMode != FLYING) {
 - 	  AzSpin =  -dAz;
 - 	  if (AzSpin < MIN_AZSPIN && AzSpin > -MIN_AZSPIN)
 - 	    AzSpin = 0;	
 - 	  ElSpin = -dEl;
 - 	  if (ElSpin < MIN_ELSPIN && ElSpin > -MIN_ELSPIN)
 - 	    ElSpin = 0; 
 - 	}
 -         AdjustingAzEl = 0;
 -         MoveOn(1);
 - 	break;
 - 
 -       case GLUT_MIDDLE_BUTTON:
 - 	EyeMove = downEyeMove;
 -       }
 -   }
 - }
 - 
 -  /*
 -   * change EyeEl and EyeAz and position when mouse is moved w/ button down
 -   */
 - void agvHandleMotion(int x, int y)
 - {
 -   int deltax = x - downx, deltay = y - downy;
 - 
 -   switch (downb) {
 -     case GLUT_LEFT_BUTTON:
 -       EyeEl  = downEl + EL_SENS * deltay;
 -       ConstrainEl();
 -       EyeAz  = downAz + AZ_SENS * deltax;
 -       dAz    = PREV_DAZ*dAz + CUR_DAZ*(lastAz - EyeAz);
 -       dEl    = PREV_DEL*dEl + CUR_DEL*(lastEl - EyeEl);
 -       lastAz = EyeAz;
 -       lastEl = EyeEl;
 -       break;
 -     case GLUT_MIDDLE_BUTTON:
 -         EyeDist = downDist + DIST_SENS*deltay;
 -         Ex = downEx - E_SENS*deltay*sin(TORAD(EyeAz))*cos(TORAD(EyeEl));
 -         Ey = downEy - E_SENS*deltay*sin(TORAD(EyeEl));
 -         Ez = downEz + E_SENS*deltay*cos(TORAD(EyeAz))*cos(TORAD(EyeEl));
 -       break;
 -   }
 -   glutPostRedisplay();
 - }
 - 
 - /***************************************************************/
 - /********************* KEYBOARD HANDLING ***********************/
 - /***************************************************************/
 - 
 -   /*
 -    * set EyeMove (current speed) for FLYING mode
 -    */
 - void SetMove(float newmove)
 - {
 -   if (newmove > MINMOVE) {
 -     EyeMove = newmove;
 -     MoveOn(1);
 -   } else {
 -     EyeMove = 0;
 -     MoveOn(0);
 -   }
 - }
 - 
 -   /*
 -    * 0->9 set speed, +/- adjust current speed  -- in FLYING mode
 -    */
 - void agvHandleKeys(unsigned char key, int, int) {
 -   if (MoveMode != FLYING)
 -     return;
 - 
 -   if (key >= '0' && key <= '9')
 -     SetMove(SPEEDFUNCTION((key-'0')));
 -   else
 -     switch(key) {
 -       case '+':  
 -         if (EyeMove == 0)
 -           SetMove(MINMOVE);
 -          else
 - 	  SetMove(EyeMove *= (1 + MOVEFRACTION));
 -         break;
 -       case '-':
 - 	SetMove(EyeMove *= (1 - MOVEFRACTION));
 -         break;
 -     }
 - }
 - 
 - /***************************************************************/
 - /*********************** VECTOR STUFF **************************/
 - /***************************************************************/
 - 
 -   /* normalizes v */
 - static void normalize(GLfloat v[3])
 - {
 -   GLfloat d = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
 - 
 -   if (d == 0)
 -     fprintf(stderr, "Zero length vector in normalize\n");
 -   else
 -     v[0] /= d; v[1] /= d; v[2] /= d;
 - }
 - 
 -   /* calculates a normalized crossproduct to v1, v2 */
 - void ncrossprod(float v1[3], float v2[3], float cp[3])
 - {
 -   cp[0] = v1[1]*v2[2] - v1[2]*v2[1];
 -   cp[1] = v1[2]*v2[0] - v1[0]*v2[2];
 -   cp[2] = v1[0]*v2[1] - v1[1]*v2[0];
 -   normalize(cp);
 - }
 - 
 - /***************************************************************/
 - /**************************** AXES *****************************/
 - /***************************************************************/
 - 
 - 
 -   /* draw axes -- was helpful to debug/design things */
 - void agvMakeAxesList(int displaylistnum)
 - {
 -   int i,j;
 -   GLfloat axes_ambuse[] =   { 0.5, 0.0, 0.0, 1.0 };
 -   glNewList(displaylistnum, GL_COMPILE);
 -   glPushAttrib(GL_LIGHTING_BIT);
 -   glMatrixMode(GL_MODELVIEW);
 -     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, axes_ambuse);
 -     glBegin(GL_LINES);
 -       glVertex3f(15, 0, 0); glVertex3f(-15, 0, 0);
 -       glVertex3f(0, 15, 0); glVertex3f(0, -15, 0);
 -       glVertex3f(0, 0, 15); glVertex3f(0, 0, -15);
 -     glEnd();
 -     for (i = 0; i < 3; i++) {
 -       glPushMatrix();
 -         glTranslatef(-10*(i==0), -10*(i==1), -10*(i==2));
 -         for (j = 0; j < 21; j++) {
 - //          glutSolidCube(0.1);
 -           glTranslatef(i==0, i==1, i==2);
 - 	}
 -       glPopMatrix();
 -     }
 -   glPopAttrib();
 -   glEndList();  
 - }
 - 
 - 
 - #endif // HAVE_GL && HAVE_GL_GLU_H
 
 
  |