You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

507 lines
13KB

  1. /*
  2. * fractviewer.cxx [from agviewer.c (version 1.0)]
  3. *
  4. * AGV: a glut viewer. Routines for viewing a 3d scene w/ glut
  5. *
  6. * See agv_example.c and agviewer.h comments within for more info.
  7. *
  8. * I welcome any feedback or improved versions!
  9. *
  10. * Philip Winston - 4/11/95
  11. * pwinston@hmc.edu
  12. * http://www.cs.hmc.edu/people/pwinston
  13. */
  14. #include <config.h>
  15. #if HAVE_GL && HAVE_GL_GLU_H
  16. # include <FL/glut.H>
  17. # include <FL/glu.h>
  18. # include <stdio.h>
  19. # include <stdlib.h>
  20. # include <math.h>
  21. # include <sys/types.h>
  22. # include <time.h>
  23. # if !defined(WIN32) && !defined(__EMX__)
  24. # include <sys/time.h>
  25. # endif // !WIN32 && !__EMX__
  26. # include "fracviewer.h"
  27. /* Some <math.h> files do not define M_PI... */
  28. #ifndef M_PI
  29. #define M_PI 3.14159265
  30. #endif
  31. /***************************************************************/
  32. /************************** SETTINGS ***************************/
  33. /***************************************************************/
  34. /* Initial polar movement settings */
  35. #define INIT_POLAR_AZ 0.0
  36. #define INIT_POLAR_EL 30.0
  37. #define INIT_DIST 4.0
  38. #define INIT_AZ_SPIN 0.5
  39. #define INIT_EL_SPIN 0.0
  40. /* Initial flying movement settings */
  41. #define INIT_EX 0.0
  42. #define INIT_EY -2.0
  43. #define INIT_EZ -2.0
  44. #define INIT_MOVE 0.01
  45. #define MINMOVE 0.001
  46. /* Start in this mode */
  47. #define INIT_MODE POLAR
  48. /* Controls: */
  49. /* map 0-9 to an EyeMove value when number key is hit in FLYING mode */
  50. #define SPEEDFUNCTION(x) ((x)*(x)*0.001)
  51. /* Multiply EyeMove by (1+-MOVEFRACTION) when +/- hit in FLYING mode */
  52. #define MOVEFRACTION 0.25
  53. /* What to multiply number of pixels mouse moved by to get rotation amount */
  54. #define EL_SENS 0.5
  55. #define AZ_SENS 0.5
  56. /* What to multiply number of pixels mouse moved by for movement amounts */
  57. #define DIST_SENS 0.01
  58. #define E_SENS 0.01
  59. /* Minimum spin to allow in polar (lower forced to zero) */
  60. #define MIN_AZSPIN 0.1
  61. #define MIN_ELSPIN 0.1
  62. /* Factors used in computing dAz and dEl (which determine AzSpin, ElSpin) */
  63. #define SLOW_DAZ 0.90
  64. #define SLOW_DEL 0.90
  65. #define PREV_DAZ 0.80
  66. #define PREV_DEL 0.80
  67. #define CUR_DAZ 0.20
  68. #define CUR_DEL 0.20
  69. /***************************************************************/
  70. /************************** GLOBALS ****************************/
  71. /***************************************************************/
  72. int MoveMode = INIT_MODE; /* FLYING or POLAR mode? */
  73. GLfloat Ex = INIT_EX, /* flying parameters */
  74. Ey = INIT_EY,
  75. Ez = INIT_EZ,
  76. EyeMove = INIT_MOVE,
  77. EyeDist = INIT_DIST, /* polar params */
  78. AzSpin = INIT_AZ_SPIN,
  79. ElSpin = INIT_EL_SPIN,
  80. EyeAz = INIT_POLAR_AZ, /* used by both */
  81. EyeEl = INIT_POLAR_EL;
  82. int agvMoving; /* Currently moving? */
  83. int downx, downy, /* for tracking mouse position */
  84. lastx, lasty,
  85. downb = -1; /* and button status */
  86. GLfloat downDist, downEl, downAz, /* for saving state of things */
  87. downEx, downEy, downEz, /* when button is pressed */
  88. downEyeMove;
  89. GLfloat dAz, dEl, lastAz, lastEl; /* to calculate spinning w/ polar motion */
  90. int AdjustingAzEl = 0;
  91. int AllowIdle, RedisplayWindow;
  92. /* If AllowIdle is 1 it means AGV will install its own idle which
  93. * will update the viewpoint as needed and send glutPostRedisplay() to the
  94. * window RedisplayWindow which was set in agvInit(). AllowIdle of 0
  95. * means AGV won't install an idle funciton, and something like
  96. * "if (agvMoving) agvMove()" should exist at the end of the running
  97. * idle function.
  98. */
  99. #define MAX(x,y) (((x) > (y)) ? (x) : (y))
  100. #define TORAD(x) ((M_PI/180.0)*(x))
  101. #define TODEG(x) ((180.0/M_PI)*(x))
  102. /***************************************************************/
  103. /************************ PROTOTYPES ***************************/
  104. /***************************************************************/
  105. /*
  106. * these are functions meant for internal use only
  107. * the other prototypes are in agviewer.h
  108. */
  109. void PolarLookFrom(GLfloat dist, GLfloat elevation, GLfloat azimuth);
  110. void FlyLookFrom(GLfloat x, GLfloat y, GLfloat z,
  111. GLfloat az, GLfloat el);
  112. int ConstrainEl(void);
  113. void MoveOn(int v);
  114. void SetMove(float newmove);
  115. static void normalize(GLfloat v[3]);
  116. void ncrossprod(float v1[3], float v2[3], float cp[3]);
  117. /***************************************************************/
  118. /************************ agvInit ******************************/
  119. /***************************************************************/
  120. void agvInit(int window)
  121. {
  122. glutMouseFunc(agvHandleButton);
  123. glutMotionFunc(agvHandleMotion);
  124. glutKeyboardFunc(agvHandleKeys);
  125. RedisplayWindow = glutGetWindow();
  126. agvSetAllowIdle(window);
  127. }
  128. /***************************************************************/
  129. /************************ VIEWPOINT STUFF **********************/
  130. /***************************************************************/
  131. /*
  132. * viewing transformation modified from page 90 of red book
  133. */
  134. void PolarLookFrom(GLfloat dist, GLfloat elevation, GLfloat azimuth)
  135. {
  136. glTranslatef(0, 0, -dist);
  137. glRotatef(elevation, 1, 0, 0);
  138. glRotatef(azimuth, 0, 1, 0);
  139. }
  140. /*
  141. * I took the idea of tracking eye position in absolute
  142. * coords and direction looking in Polar form from denis
  143. */
  144. void FlyLookFrom(GLfloat x, GLfloat y, GLfloat z, GLfloat az, GLfloat el)
  145. {
  146. float lookat[3], perp[3], up[3];
  147. lookat[0] = sin(TORAD(az))*cos(TORAD(el));
  148. lookat[1] = sin(TORAD(el));
  149. lookat[2] = -cos(TORAD(az))*cos(TORAD(el));
  150. normalize(lookat);
  151. perp[0] = lookat[2];
  152. perp[1] = 0;
  153. perp[2] = -lookat[0];
  154. normalize(perp);
  155. ncrossprod(lookat, perp, up);
  156. gluLookAt(x, y, z,
  157. x+lookat[0], y+lookat[1], z+lookat[2],
  158. up[0], up[1], up[2]);
  159. }
  160. /*
  161. * Call viewing transformation based on movement mode
  162. */
  163. void agvViewTransform(void)
  164. {
  165. switch (MoveMode) {
  166. case FLYING:
  167. FlyLookFrom(Ex, Ey, Ez, EyeAz, EyeEl);
  168. break;
  169. case POLAR:
  170. PolarLookFrom(EyeDist, EyeEl, EyeAz);
  171. break;
  172. }
  173. }
  174. /*
  175. * keep them vertical; I think this makes a lot of things easier,
  176. * but maybe it wouldn't be too hard to adapt things to let you go
  177. * upside down
  178. */
  179. int ConstrainEl(void)
  180. {
  181. if (EyeEl <= -90) {
  182. EyeEl = -89.99;
  183. return 1;
  184. } else if (EyeEl >= 90) {
  185. EyeEl = 89.99;
  186. return 1;
  187. }
  188. return 0;
  189. }
  190. /*
  191. * Idle Function - moves eyeposition
  192. */
  193. void agvMove(void)
  194. {
  195. switch (MoveMode) {
  196. case FLYING:
  197. Ex += EyeMove*sin(TORAD(EyeAz))*cos(TORAD(EyeEl));
  198. Ey += EyeMove*sin(TORAD(EyeEl));
  199. Ez -= EyeMove*cos(TORAD(EyeAz))*cos(TORAD(EyeEl));
  200. break;
  201. case POLAR:
  202. EyeEl += ElSpin;
  203. EyeAz += AzSpin;
  204. if (ConstrainEl()) { /* weird spin thing to make things look */
  205. ElSpin = -ElSpin; /* look better when you are kept from going */
  206. /* upside down while spinning - Isn't great */
  207. if (fabs(ElSpin) > fabs(AzSpin))
  208. AzSpin = fabs(ElSpin) * ((AzSpin > 0) ? 1 : -1);
  209. }
  210. break;
  211. }
  212. if (AdjustingAzEl) {
  213. dAz *= SLOW_DAZ;
  214. dEl *= SLOW_DEL;
  215. }
  216. if (AllowIdle) {
  217. glutSetWindow(RedisplayWindow);
  218. glutPostRedisplay();
  219. }
  220. }
  221. /*
  222. * Don't install agvMove as idle unless we will be updating the view
  223. * and we've been given a RedisplayWindow
  224. */
  225. void MoveOn(int v)
  226. {
  227. if (v && ((MoveMode == FLYING && EyeMove != 0) ||
  228. (MoveMode == POLAR &&
  229. (AzSpin != 0 || ElSpin != 0 || AdjustingAzEl)))) {
  230. agvMoving = 1;
  231. if (AllowIdle)
  232. glutIdleFunc(agvMove);
  233. } else {
  234. agvMoving = 0;
  235. if (AllowIdle)
  236. glutIdleFunc(NULL);
  237. }
  238. }
  239. /*
  240. * set new redisplay window. If <= 0 it means we are not to install
  241. * an idle function and will rely on whoever does install one to
  242. * put statement like "if (agvMoving) agvMove();" at end of it
  243. */
  244. void agvSetAllowIdle(int allowidle)
  245. {
  246. if ((AllowIdle = allowidle))
  247. MoveOn(1);
  248. }
  249. /*
  250. * when moving to flying we stay in the same spot, moving to polar we
  251. * reset since we have to be looking at the origin (though a pivot from
  252. * current position to look at origin might be cooler)
  253. */
  254. void agvSwitchMoveMode(int move)
  255. {
  256. switch (move) {
  257. case FLYING:
  258. if (MoveMode == FLYING) return;
  259. Ex = -EyeDist*sin(TORAD(EyeAz))*cos(TORAD(EyeEl));
  260. Ey = EyeDist*sin(TORAD(EyeEl));
  261. Ez = EyeDist*(cos(TORAD(EyeAz))*cos(TORAD(EyeEl)));
  262. EyeAz = EyeAz;
  263. EyeEl = -EyeEl;
  264. EyeMove = INIT_MOVE;
  265. break;
  266. case POLAR:
  267. EyeDist = INIT_DIST;
  268. EyeAz = INIT_POLAR_AZ;
  269. EyeEl = INIT_POLAR_EL;
  270. AzSpin = INIT_AZ_SPIN;
  271. ElSpin = INIT_EL_SPIN;
  272. break;
  273. }
  274. MoveMode = move;
  275. MoveOn(1);
  276. glutPostRedisplay();
  277. }
  278. /***************************************************************/
  279. /******************* MOUSE HANDLING ***********************/
  280. /***************************************************************/
  281. void agvHandleButton(int button, int state, int x, int y)
  282. {
  283. if (state == GLUT_DOWN && downb == -1) {
  284. lastx = downx = x;
  285. lasty = downy = y;
  286. downb = button;
  287. switch (button) {
  288. case GLUT_LEFT_BUTTON:
  289. lastEl = downEl = EyeEl;
  290. lastAz = downAz = EyeAz;
  291. AzSpin = ElSpin = dAz = dEl = 0;
  292. AdjustingAzEl = 1;
  293. MoveOn(1);
  294. break;
  295. case GLUT_MIDDLE_BUTTON:
  296. downDist = EyeDist;
  297. downEx = Ex;
  298. downEy = Ey;
  299. downEz = Ez;
  300. downEyeMove = EyeMove;
  301. EyeMove = 0;
  302. }
  303. } else if (state == GLUT_UP && button == downb) {
  304. downb = -1;
  305. switch (button) {
  306. case GLUT_LEFT_BUTTON:
  307. if (MoveMode != FLYING) {
  308. AzSpin = -dAz;
  309. if (AzSpin < MIN_AZSPIN && AzSpin > -MIN_AZSPIN)
  310. AzSpin = 0;
  311. ElSpin = -dEl;
  312. if (ElSpin < MIN_ELSPIN && ElSpin > -MIN_ELSPIN)
  313. ElSpin = 0;
  314. }
  315. AdjustingAzEl = 0;
  316. MoveOn(1);
  317. break;
  318. case GLUT_MIDDLE_BUTTON:
  319. EyeMove = downEyeMove;
  320. }
  321. }
  322. }
  323. /*
  324. * change EyeEl and EyeAz and position when mouse is moved w/ button down
  325. */
  326. void agvHandleMotion(int x, int y)
  327. {
  328. int deltax = x - downx, deltay = y - downy;
  329. switch (downb) {
  330. case GLUT_LEFT_BUTTON:
  331. EyeEl = downEl + EL_SENS * deltay;
  332. ConstrainEl();
  333. EyeAz = downAz + AZ_SENS * deltax;
  334. dAz = PREV_DAZ*dAz + CUR_DAZ*(lastAz - EyeAz);
  335. dEl = PREV_DEL*dEl + CUR_DEL*(lastEl - EyeEl);
  336. lastAz = EyeAz;
  337. lastEl = EyeEl;
  338. break;
  339. case GLUT_MIDDLE_BUTTON:
  340. EyeDist = downDist + DIST_SENS*deltay;
  341. Ex = downEx - E_SENS*deltay*sin(TORAD(EyeAz))*cos(TORAD(EyeEl));
  342. Ey = downEy - E_SENS*deltay*sin(TORAD(EyeEl));
  343. Ez = downEz + E_SENS*deltay*cos(TORAD(EyeAz))*cos(TORAD(EyeEl));
  344. break;
  345. }
  346. glutPostRedisplay();
  347. }
  348. /***************************************************************/
  349. /********************* KEYBOARD HANDLING ***********************/
  350. /***************************************************************/
  351. /*
  352. * set EyeMove (current speed) for FLYING mode
  353. */
  354. void SetMove(float newmove)
  355. {
  356. if (newmove > MINMOVE) {
  357. EyeMove = newmove;
  358. MoveOn(1);
  359. } else {
  360. EyeMove = 0;
  361. MoveOn(0);
  362. }
  363. }
  364. /*
  365. * 0->9 set speed, +/- adjust current speed -- in FLYING mode
  366. */
  367. void agvHandleKeys(unsigned char key, int, int) {
  368. if (MoveMode != FLYING)
  369. return;
  370. if (key >= '0' && key <= '9')
  371. SetMove(SPEEDFUNCTION((key-'0')));
  372. else
  373. switch(key) {
  374. case '+':
  375. if (EyeMove == 0)
  376. SetMove(MINMOVE);
  377. else
  378. SetMove(EyeMove *= (1 + MOVEFRACTION));
  379. break;
  380. case '-':
  381. SetMove(EyeMove *= (1 - MOVEFRACTION));
  382. break;
  383. }
  384. }
  385. /***************************************************************/
  386. /*********************** VECTOR STUFF **************************/
  387. /***************************************************************/
  388. /* normalizes v */
  389. static void normalize(GLfloat v[3])
  390. {
  391. GLfloat d = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
  392. if (d == 0)
  393. fprintf(stderr, "Zero length vector in normalize\n");
  394. else
  395. v[0] /= d; v[1] /= d; v[2] /= d;
  396. }
  397. /* calculates a normalized crossproduct to v1, v2 */
  398. void ncrossprod(float v1[3], float v2[3], float cp[3])
  399. {
  400. cp[0] = v1[1]*v2[2] - v1[2]*v2[1];
  401. cp[1] = v1[2]*v2[0] - v1[0]*v2[2];
  402. cp[2] = v1[0]*v2[1] - v1[1]*v2[0];
  403. normalize(cp);
  404. }
  405. /***************************************************************/
  406. /**************************** AXES *****************************/
  407. /***************************************************************/
  408. /* draw axes -- was helpful to debug/design things */
  409. void agvMakeAxesList(int displaylistnum)
  410. {
  411. int i,j;
  412. GLfloat axes_ambuse[] = { 0.5, 0.0, 0.0, 1.0 };
  413. glNewList(displaylistnum, GL_COMPILE);
  414. glPushAttrib(GL_LIGHTING_BIT);
  415. glMatrixMode(GL_MODELVIEW);
  416. glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, axes_ambuse);
  417. glBegin(GL_LINES);
  418. glVertex3f(15, 0, 0); glVertex3f(-15, 0, 0);
  419. glVertex3f(0, 15, 0); glVertex3f(0, -15, 0);
  420. glVertex3f(0, 0, 15); glVertex3f(0, 0, -15);
  421. glEnd();
  422. for (i = 0; i < 3; i++) {
  423. glPushMatrix();
  424. glTranslatef(-10*(i==0), -10*(i==1), -10*(i==2));
  425. for (j = 0; j < 21; j++) {
  426. // glutSolidCube(0.1);
  427. glTranslatef(i==0, i==1, i==2);
  428. }
  429. glPopMatrix();
  430. }
  431. glPopAttrib();
  432. glEndList();
  433. }
  434. #endif // HAVE_GL && HAVE_GL_GLU_H