diff options
| author | Michael R Sweet <michael.r.sweet@gmail.com> | 2002-01-03 14:08:08 +0000 |
|---|---|---|
| committer | Michael R Sweet <michael.r.sweet@gmail.com> | 2002-01-03 14:08:08 +0000 |
| commit | 81be28e2dd5c7609ba9a07f20646b05bcb53e727 (patch) | |
| tree | 113678c885d4f1ef191a67b9c6daa74b708628b1 /test/fracviewer.cxx | |
| parent | 1775984dbea2b186a9cd7b5a8b697558028e7da9 (diff) | |
Fixup fractals demo so it doesn't get way ahead of display - some Linux
OpenGL implementations can queue dozens of frames...
Also fix controls in "flying" mode - the Y axis was reversed.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@1907 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'test/fracviewer.cxx')
| -rw-r--r-- | test/fracviewer.cxx | 510 |
1 files changed, 510 insertions, 0 deletions
diff --git a/test/fracviewer.cxx b/test/fracviewer.cxx new file mode 100644 index 000000000..5ed52a3c7 --- /dev/null +++ b/test/fracviewer.cxx @@ -0,0 +1,510 @@ +/* + * 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> +# ifdef __APPLE__ +# include <OpenGL/glu.h> +# else +# include <GL/glu.h> // added for FLTK +# endif + +# 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 |
