From 81be28e2dd5c7609ba9a07f20646b05bcb53e727 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Thu, 3 Jan 2002 14:08:08 +0000 Subject: 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 --- CHANGES | 5 + test/Makefile | 8 +- test/fractals.cxx | 37 ++-- test/fracviewer.c | 496 -------------------------------------------------- test/fracviewer.cxx | 510 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test/fracviewer.h | 1 + test/makedepend | 28 ++- 7 files changed, 562 insertions(+), 523 deletions(-) delete mode 100644 test/fracviewer.c create mode 100644 test/fracviewer.cxx diff --git a/CHANGES b/CHANGES index 4167e1266..2551d90e4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,10 @@ CHANGES IN FLTK 1.1.0b9 + - The fractals demo would get far ahead of the UI with + some Linux OpenGL drivers. Now use glFinish() instead + of glFlush() so we are at most 1 frame ahead. + - The fractals demo Y axis controls were backwards for + the "flying" mode. - MacOS: cleaned up src/Fl_mac.cxx - MacOS: fixed Fl::wait(0.0), fixed Cmd-Q handling - Update CygWin support for Fl::add_fd(). diff --git a/test/Makefile b/test/Makefile index 035f03597..a170ea90a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,5 +1,5 @@ # -# "$Id: Makefile,v 1.19.2.7.2.26 2002/01/01 15:11:32 easysw Exp $" +# "$Id: Makefile,v 1.19.2.7.2.27 2002/01/03 14:08:08 easysw Exp $" # # Test/example program makefile for the Fast Light Tool Kit (FLTK). # @@ -207,9 +207,9 @@ cube$(EXEEXT): cube.o echo Linking $@... $(CXX) -I.. $(CXXFLAGS) cube.o $(LINKFLTKGL) $(LINKFLTK) $(GLDLIBS) -o $@ $(POSTBUILD) $@ ../FL/mac.r -fractals$(EXEEXT): fractals.o +fractals$(EXEEXT): fractals.o fracviewer.o echo Linking $@... - $(CXX) -I.. $(CXXFLAGS) fractals.o $(LINKFLTKGL) $(LINKFLTK) $(GLDLIBS) -o $@ + $(CXX) -I.. $(CXXFLAGS) fractals.o fracviewer.o $(LINKFLTKGL) $(LINKFLTK) $(GLDLIBS) -o $@ $(POSTBUILD) $@ ../FL/mac.r fullscreen$(EXEEXT): fullscreen.o echo Linking $@... @@ -261,5 +261,5 @@ uninstall: @echo Nothing to uninstall in test directory. # -# End of "$Id: Makefile,v 1.19.2.7.2.26 2002/01/01 15:11:32 easysw Exp $". +# End of "$Id: Makefile,v 1.19.2.7.2.27 2002/01/03 14:08:08 easysw Exp $". # diff --git a/test/fractals.cxx b/test/fractals.cxx index 9f99b91fc..cfe4c6907 100644 --- a/test/fractals.cxx +++ b/test/fractals.cxx @@ -1,11 +1,11 @@ // -// "$Id: fractals.cxx,v 1.5.2.6.2.3 2002/01/01 15:11:33 easysw Exp $" +// "$Id: fractals.cxx,v 1.5.2.6.2.4 2002/01/03 14:08:08 easysw Exp $" // // Fractal drawing demo for the Fast Light Tool Kit (FLTK). // // This is a GLUT demo program, with modifications to -// demonstrate how to add fltk controls to a glut program. The glut -// code is unchanged except for the end (search for fltk to find changes). +// demonstrate how to add FLTK controls to a GLUT program. The GLUT +// code is unchanged except for the end (search for FLTK to find changes). // // Copyright 1998-2002 by Bill Spitzak and others. // @@ -63,9 +63,9 @@ int main(int, char**) { #include #ifdef __APPLE__ -# include +# include #else -# include // added for fltk +# include // added for FLTK #endif #include @@ -76,14 +76,14 @@ int main(int, char**) { #include /* for random seed */ -#include "fracviewer.c" // changed from .h for fltk +#include "fracviewer.h" #if defined(WIN32) || defined(__EMX__) -# define drand48() (((float) rand())/((float) RAND_MAX)) -# define srand48(x) (srand((x))) +# define drand48() (((float) rand())/((float) RAND_MAX)) +# define srand48(x) (srand((x))) #elif defined __APPLE__ -# define drand48() (((float) rand())/((float) RAND_MAX)) -# define srand48(x) (srand((x))) +# define drand48() (((float) rand())/((float) RAND_MAX)) +# define srand48(x) (srand((x))) #endif typedef enum { NOTALLOWED, MOUNTAIN, TREE, ISLAND, BIGMTN, STEM, LEAF, @@ -624,7 +624,6 @@ void reshape(int w, int h) void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glFlush(); glMatrixMode(GL_PROJECTION); glPopMatrix(); @@ -645,8 +644,12 @@ void display(void) if (DrawAxes) glCallList(AXES); - glutSwapBuffers(); - glFlush(); + // + // Use glFinish() instead of glFlush() to avoid getting many frames + // ahead of the display (problem with some Linux OpenGL implementations...) + // + + glFinish(); } void visible(int v) @@ -742,7 +745,7 @@ void MenuInit(void) /**************************** MAIN *****************************/ /***************************************************************/ -// fltk-style callbacks to Glut menu callback translators: +// FLTK-style callbacks to Glut menu callback translators: void setlevel(Fl_Widget*, void *value) {setlevel(long(value));} void choosefract(Fl_Widget*, void *value) {choosefract(long(value));} @@ -755,9 +758,9 @@ void handlemenu(Fl_Widget*, void *value) {handlemenu(long(value));} int main(int argc, char** argv) { -// glutInit(&argc, argv); // this line removed for fltk +// glutInit(&argc, argv); // this line removed for FLTK - // create fltk window: + // create FLTK window: Fl_Window window(512+20, 512+100); window.resizable(window); @@ -813,5 +816,5 @@ int main(int argc, char** argv) #endif // -// End of "$Id: fractals.cxx,v 1.5.2.6.2.3 2002/01/01 15:11:33 easysw Exp $". +// End of "$Id: fractals.cxx,v 1.5.2.6.2.4 2002/01/03 14:08:08 easysw Exp $". // diff --git a/test/fracviewer.c b/test/fracviewer.c deleted file mode 100644 index 9d926c175..000000000 --- a/test/fracviewer.c +++ /dev/null @@ -1,496 +0,0 @@ -/* - * fractviewer.c [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 -#include -#include -#include - -#include "fracviewer.h" - -/* Some 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]); -static 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 * ((MoveMode == FLYING) ? -deltay : 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 */ -static 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(); -} - - 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 + +#if HAVE_GL && HAVE_GL_GLU_H +# include +# ifdef __APPLE__ +# include +# else +# include // added for FLTK +# endif + +# include +# include +# include +# include +# include +# if !defined(WIN32) && !defined(__EMX__) +# include +# endif // !WIN32 && !__EMX__ + +# include "fracviewer.h" + +/* Some 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 diff --git a/test/fracviewer.h b/test/fracviewer.h index d217e9aa6..b51e65e8c 100644 --- a/test/fracviewer.h +++ b/test/fracviewer.h @@ -95,6 +95,7 @@ void agvMakeAxesList(int displaylist); +void ncrossprod(float v1[3], float v2[3], float cp[3]); diff --git a/test/makedepend b/test/makedepend index ee3f5b593..92f517b13 100644 --- a/test/makedepend +++ b/test/makedepend @@ -77,6 +77,11 @@ cube.o: ../FL/Fl_Button.H ../FL/Fl_Radio_Light_Button.H cube.o: ../FL/Fl_Light_Button.H ../FL/Fl_Button.H ../FL/Fl_Slider.H cube.o: ../FL/Fl_Valuator.H ../FL/Fl_Gl_Window.H ../FL/Fl_Window.H ../FL/gl.h CubeMain.o: ../config.h ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H +CubeMain.o: CubeViewUI.h ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H +CubeMain.o: ../FL/Fl_Group.H ../FL/Fl_Roller.H ../FL/Fl_Valuator.H +CubeMain.o: ../FL/Fl_Slider.H ../FL/Fl_Box.H CubeView.h ../FL/Fl_Gl_Window.H +CubeMain.o: ../FL/Fl_Window.H ../FL/gl.h ../FL/Fl_Value_Slider.H +CubeMain.o: ../FL/Fl_Slider.H CubeView.o: CubeView.h ../config.h ../FL/Fl.H ../FL/Enumerations.H CubeView.o: ../FL/Fl_Export.H ../FL/Fl_Gl_Window.H ../FL/Fl_Window.H CubeView.o: ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/gl.h @@ -142,9 +147,8 @@ forms.o: ../FL/Fl_Input.H ../FL/Fl_Menu_Button.H ../FL/Fl_Positioner.H forms.o: ../FL/Fl_Value_Slider.H ../FL/Fl_Timer.H srs.xbm fractals.o: ../config.h ../FL/glut.H ../FL/gl.h ../FL/Enumerations.H fractals.o: ../FL/Fl_Export.H ../FL/Fl.H ../FL/Fl_Gl_Window.H -fractals.o: ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H fracviewer.c -fractals.o: ../GL/glut.h fracviewer.h ../FL/Fl_Button.H ../FL/Fl_Group.H -fractals.o: ../FL/Fl_Window.H +fractals.o: ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H fracviewer.h +fractals.o: ../FL/Fl_Button.H ../FL/Fl_Group.H ../FL/Fl_Window.H fullscreen.o: ../config.h ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H fullscreen.o: ../FL/Fl_Single_Window.H ../FL/Fl_Window.H ../FL/Fl_Group.H fullscreen.o: ../FL/Fl_Widget.H ../FL/Fl_Hor_Slider.H ../FL/Fl_Slider.H @@ -192,6 +196,10 @@ input.o: ../FL/Fl_Multiline_Input.H ../FL/Fl_Button.H input.o: ../FL/Fl_Toggle_Button.H ../FL/Fl_Button.H ../FL/Fl_Color_Chooser.H input.o: ../FL/Fl_Group.H ../FL/Fl_Box.H ../FL/Fl_Return_Button.H input.o: ../FL/Fl_Choice.H ../FL/Fl_Value_Input.H ../FL/Fl_Valuator.H +keyboard.o: keyboard_ui.h ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H +keyboard.o: keyboard.h ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H +keyboard.o: ../FL/Fl_Button.H ../FL/Fl_Output.H ../FL/Fl_Input_.H +keyboard.o: ../FL/Fl_Box.H ../FL/Fl_Dial.H ../FL/Fl_Valuator.H label.o: ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H label.o: ../FL/Fl_Double_Window.H ../FL/Fl_Window.H ../FL/Fl_Group.H label.o: ../FL/Fl_Widget.H ../FL/Fl_Box.H ../FL/Fl_Hor_Value_Slider.H @@ -203,7 +211,11 @@ line_style.o: ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H line_style.o: ../FL/Fl_Value_Slider.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H line_style.o: ../FL/fl_draw.H ../FL/Fl_Choice.H list_visuals.o: ../config.h -mandelbrot.o: ../FL/fl_draw.H ../FL/Enumerations.H ../FL/Fl_Export.H +mandelbrot.o: mandelbrot_ui.h ../FL/Fl.H ../FL/Enumerations.H +mandelbrot.o: ../FL/Fl_Export.H mandelbrot.h ../FL/Fl_Box.H ../FL/Fl_Slider.H +mandelbrot.o: ../FL/Fl_Valuator.H ../FL/Fl_Window.H ../FL/Fl_Group.H +mandelbrot.o: ../FL/Fl_Widget.H ../FL/Fl_Input.H ../FL/Fl_Input_.H +mandelbrot.o: ../FL/fl_draw.H menubar.o: ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Box.H menubar.o: ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H menubar.o: ../FL/Fl_Menu_Bar.H ../FL/Fl_Menu_.H ../FL/Fl_Menu_Item.H @@ -273,8 +285,12 @@ shape.o: ../config.h ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H shape.o: ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H shape.o: ../FL/Fl_Hor_Slider.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H shape.o: ../FL/math.h ../FL/gl.h ../FL/Fl_Gl_Window.H ../FL/Fl_Window.H -shiny.o: ../config.h ../FL/fl_message.H ../FL/fl_ask.H ../FL/Enumerations.H -shiny.o: ../FL/Fl_Export.H ../FL/fl_draw.H ../FL/gl.h +shiny.o: ../config.h shiny_panel.h ../FL/Fl.H ../FL/Enumerations.H +shiny.o: ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H +shiny.o: ../FL/Fl_Widget.H ../FL/Fl_Box.H ../FL/Fl_Group.H ../FL/Fl_Button.H +shiny.o: ../FL/Fl_Value_Slider.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H +shiny.o: ../FL/Fl_Slider.H ../FL/fl_message.H ../FL/fl_ask.H ../FL/fl_draw.H +shiny.o: ../FL/gl.h subwindow.o: ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H subwindow.o: ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H subwindow.o: ../FL/Fl_Toggle_Button.H ../FL/Fl_Button.H -- cgit v1.2.3