glui.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:14k
源码类别:

GIS编程

开发平台:

Visual C++

  1. /*
  2.   glui.c
  3.   Nate Robins, 1997.
  4.   OpenGL based user interface.
  5.  */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <GL/glut.h>
  9. #define GLUI_BORDER  3
  10. #define GLUI_KNOB   40
  11. #define GLUI_RAISED  1
  12. #define GLUI_SUNKEN  0
  13. #define GLUI_HORIZONTAL 0
  14. #define GLUI_VERTICAL   1
  15. #define GLUI_LESS -1
  16. #define GLUI_HIT   0
  17. #define GLUI_MORE  1
  18. #define GLUI_HILITE 0.15
  19. typedef struct _GLUIslider {
  20.     int type; /* vertical/horizontal */
  21.     int parent; /* parent of this slider */
  22.     int window; /* this sliders window */
  23.     int win_x; /* slider window x (parent relative) */
  24.     int win_y; /* slider window y (parent relative) */
  25.     int win_w; /* slider window width */
  26.     int win_h; /* slider window height */
  27.     int length; /* length of the slider in pixels */
  28.     int knob; /* position of the knob in pixels */
  29.     int lit; /* currently lit? */
  30.     void (*update)(float); /* callback for updating (returns %) */
  31.     struct _GLUIslider* next;
  32. } GLUIslider;
  33. static GLUIslider* _gluiSliders = NULL;
  34. static GLUIslider* _gluiHit = NULL;
  35. static GLUIslider*
  36. _gluiCurrentSlider(void)
  37. {
  38.     GLUIslider* slider = _gluiSliders;
  39.     int window = glutGetWindow();
  40.     while(slider) {
  41. if (slider->window == window)
  42.     break;
  43. slider = slider->next;
  44.     }
  45.     if (!slider)
  46. printf("glui: _gluiCurrentSlider() failed!n");
  47.     return slider;
  48. }
  49. static void
  50. _gluiEmboss(int raised, int lit, int x, int y, int width, int height)
  51. {
  52.     int i;
  53.     float c;
  54.     for (i = 0; i < GLUI_BORDER; i++) {
  55. c = (float)i / (GLUI_BORDER * 5) + (lit ? GLUI_HILITE : 0.0);
  56. if (raised)
  57.     glColor3f(0.275+c, 0.2+c, 0.2+c);
  58. else
  59.     glColor3f(0.875-c, 0.8-c, 0.8-c);
  60. glBegin(GL_LINE_STRIP);
  61. glVertex2f(x+i+1, y+i);
  62. glVertex2f(x+width-i-1, y+i);
  63. glVertex2f(x+width-i-1, y+height-i);
  64. glEnd();
  65.     }
  66.     for (i = 0; i < GLUI_BORDER; i++) {
  67. c = (float)i / (GLUI_BORDER * 5);
  68. if (raised)
  69.     glColor3f(0.875-c, 0.8-c, 0.8-c);
  70. else
  71.     glColor3f(0.275+c, 0.2+c, 0.2+c);
  72. glBegin(GL_LINE_STRIP);
  73. glVertex2f(x+i, y+i);
  74. glVertex2f(x+i, y+height-i-1);
  75. glVertex2f(x+width-i-1, y+height-i-1);
  76. glEnd();
  77.     }
  78.     c = lit ? GLUI_HILITE : 0.0;
  79.     if (raised)
  80. glColor3f(0.575+c, 0.5+c, 0.5+c);
  81.     else
  82. glColor3f(0.475+c, 0.3+c, 0.3+c);
  83.     glRectf(x+i, y+i, x+width-i, y+height-i);
  84. }
  85. static void
  86. _gluiDisplay(void)
  87. {
  88.     int lit;
  89.     GLUIslider* slider = _gluiCurrentSlider();
  90.     lit = slider->lit ? GLUI_HILITE : 0.0;
  91.     glClear(GL_COLOR_BUFFER_BIT);
  92.     if (slider->type == GLUI_HORIZONTAL) {
  93. _gluiEmboss(GLUI_SUNKEN, 0, /* never lit */
  94.     0, 0, slider->length, slider->win_h);
  95. _gluiEmboss(GLUI_RAISED, slider->lit, 
  96.     slider->knob - GLUI_KNOB/2, GLUI_BORDER,
  97.     GLUI_KNOB + GLUI_BORDER, slider->win_h - GLUI_BORDER*2);
  98. /* XXX why is it GLUI_KNOB+GLUI_BORDER ? */
  99. glColor3f(0.975+lit, 0.9+lit, 0.9+lit);
  100. glBegin(GL_LINES);
  101. glVertex2f(slider->knob-2, GLUI_BORDER*2-1);
  102. glVertex2f(slider->knob-2, slider->win_h-GLUI_BORDER*2+1);
  103. glVertex2f(slider->knob+1, GLUI_BORDER*2-1);
  104. glVertex2f(slider->knob+1, slider->win_h-GLUI_BORDER*2+1);
  105. glVertex2f(slider->knob+4, GLUI_BORDER*2-1);
  106. glVertex2f(slider->knob+4, slider->win_h-GLUI_BORDER*2+1);
  107. glEnd();
  108. glColor3f(0.175+lit, 0.1+lit, 0.1+lit);
  109. glBegin(GL_LINES);
  110. glVertex2f(slider->knob-3, GLUI_BORDER*2-1);
  111. glVertex2f(slider->knob-3, slider->win_h-GLUI_BORDER*2+1);
  112. glVertex2f(slider->knob+0, GLUI_BORDER*2-1);
  113. glVertex2f(slider->knob+0, slider->win_h-GLUI_BORDER*2+1);
  114. glVertex2f(slider->knob+3, GLUI_BORDER*2-1);
  115. glVertex2f(slider->knob+3, slider->win_h-GLUI_BORDER*2+1);
  116. glEnd();
  117.     } else {
  118. _gluiEmboss(GLUI_SUNKEN, 0, /* never lit */
  119.     0, 0, slider->win_w, slider->length);
  120. _gluiEmboss(GLUI_RAISED, slider->lit, 
  121.     GLUI_BORDER, slider->knob - GLUI_KNOB/2,
  122.     slider->win_w - GLUI_BORDER*2, GLUI_KNOB + GLUI_BORDER);
  123. /* XXX why is it GLUI_KNOB+GLUI_BORDER ? */
  124. glColor3f(0.175+lit, 0.1+lit, 0.1+lit);
  125. glBegin(GL_LINES);
  126. glVertex2f(GLUI_BORDER*2-1, slider->knob-2);
  127. glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob-2);
  128. glVertex2f(GLUI_BORDER*2-1, slider->knob+1);
  129. glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob+1);
  130. glVertex2f(GLUI_BORDER*2-1, slider->knob+4);
  131. glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob+4);
  132. glEnd();
  133. glColor3f(0.975+lit, 0.9+lit, 0.9+lit);
  134. glBegin(GL_LINES);
  135. glVertex2f(GLUI_BORDER*2-1, slider->knob-3);
  136. glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob-3);
  137. glVertex2f(GLUI_BORDER*2-1, slider->knob+0);
  138. glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob+0);
  139. glVertex2f(GLUI_BORDER*2-1, slider->knob+3);
  140. glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob+3);
  141. glEnd();
  142.     }
  143.     glutSwapBuffers();
  144. }
  145. static int
  146. _gluiHitKnob(GLUIslider* slider, int x, int y)
  147. {
  148.     if (slider->type == GLUI_HORIZONTAL) {
  149. /* we know that we don't have to test the y coordinate because
  150.    the mouse came down in the window (this means that they can
  151.    hit the borders and still move the knob, but that's okay).
  152.  */
  153. if (x > slider->knob - GLUI_KNOB/2 && x < slider->knob + GLUI_KNOB/2)
  154.     return GLUI_HIT;
  155. else if (x < slider->knob)
  156.     return GLUI_LESS;
  157. else
  158.     return GLUI_MORE;
  159.     } else {
  160. /* we know that we don't have to test the x coordinate because
  161.    the mouse came down in the window (this means that they can
  162.    hit the borders and still move the knob, but that's okay).
  163.  */
  164. if (y > slider->knob - GLUI_KNOB/2 && y < slider->knob + GLUI_KNOB/2)
  165.     return GLUI_HIT;
  166. else if (y < slider->knob)
  167.     return GLUI_LESS;
  168. else
  169.     return GLUI_MORE;
  170.     }
  171. }
  172. static void
  173. _gluiConstrainKnob(GLUIslider* slider)
  174. {
  175.     if (slider->knob > slider->length - GLUI_BORDER*2 - GLUI_KNOB/2)
  176. slider->knob = slider->length - GLUI_BORDER*2 - GLUI_KNOB/2;
  177.     else if (slider->knob < GLUI_BORDER + GLUI_KNOB/2)
  178. slider->knob = GLUI_BORDER + GLUI_KNOB/2;
  179. }
  180. static float
  181. _gluiKnobPercent(GLUIslider* slider)
  182. {
  183.     return (float)(slider->knob - GLUI_KNOB/2 - GLUI_BORDER) /
  184. (slider->length - GLUI_BORDER*3 - GLUI_KNOB);
  185. }
  186. static int
  187. _gluiKnobPosition(GLUIslider* slider, float percent)
  188. {
  189.     return GLUI_BORDER + GLUI_KNOB/2 + percent * 
  190. (slider->length - GLUI_BORDER*3 - GLUI_KNOB);
  191. }
  192. static int _gluiX;
  193. static int _gluiY;
  194. static int _gluiMouseDown;
  195. static void
  196. _gluiTimer(int value)
  197. {
  198.     GLUIslider* slider = (GLUIslider*)value;
  199.     float percent;
  200.     percent = _gluiKnobPercent(slider); 
  201.     if (_gluiMouseDown != 0 && percent > 0.0 && percent < 1.0) {
  202. if (_gluiMouseDown == GLUI_LESS) {
  203.     slider->knob -= slider->length / 25.0;
  204.     _gluiConstrainKnob(slider);
  205. } else {
  206.     slider->knob += slider->length / 25.0;
  207.     _gluiConstrainKnob(slider);
  208. }
  209. glutSetWindow(slider->window);
  210.   glutPostRedisplay();
  211. slider->update(_gluiKnobPercent(slider));
  212. glutTimerFunc(20, _gluiTimer, (int)slider);
  213.     }
  214. }
  215. static void
  216. _gluiConvertY(GLUIslider* slider, int* y)
  217. {
  218.     if (slider->win_h < 0) {
  219. glutSetWindow(slider->parent);
  220. *y = glutGet(GLUT_WINDOW_HEIGHT) + slider->win_h - slider->win_y - *y;
  221. glutSetWindow(slider->window);
  222.     } else {
  223. *y = slider->win_h - *y;
  224.     }
  225. }
  226. /* ARGSUSED */
  227. static void
  228. _gluiMouse(int button, int state, int x, int y)
  229. {
  230.     GLUIslider* slider = _gluiCurrentSlider();
  231.     int side;
  232.     _gluiConvertY(slider, &y);
  233.     _gluiX = x;
  234.     _gluiY = y;
  235.     _gluiHit = NULL;
  236.     _gluiMouseDown = GL_FALSE;
  237.     if (state == GLUT_DOWN) {
  238. side = _gluiHitKnob(slider, x, y);
  239. if (side == GLUI_HIT) {
  240.     _gluiHit = slider;
  241. } else if (side == GLUI_LESS) {
  242.     slider->knob -= slider->length / 25.0;
  243.     _gluiConstrainKnob(slider);
  244. } else {
  245.     slider->knob += slider->length / 25.0;
  246.     _gluiConstrainKnob(slider);
  247. }
  248. glutPostRedisplay();
  249. slider->update(_gluiKnobPercent(slider));
  250. _gluiMouseDown = side;
  251. if (side != 0) {
  252.     glutTimerFunc(500, _gluiTimer, (int)slider);
  253. }
  254.     } else {
  255. slider->lit = GL_FALSE;
  256.     }
  257. }
  258. static void
  259. _gluiMotion(int x, int y)
  260. {
  261.     GLUIslider* slider = _gluiHit;
  262.     if (slider) {
  263. _gluiConvertY(slider, &y);
  264. if (slider->type == GLUI_HORIZONTAL) {
  265.     /* clamp the incoming old position, or else the knob will
  266.                possibly "jump" due to the false delta. */
  267.     if (_gluiX < GLUI_BORDER+1)
  268. _gluiX = GLUI_BORDER+1;
  269.     if (_gluiX > slider->length - GLUI_BORDER*2)
  270. _gluiX = slider->length - GLUI_BORDER*2;
  271.     /* we don't want to take any action if the mouse pointer
  272.                has moved passed the extents of the slider. */
  273.     if (x > GLUI_BORDER && x < slider->length - GLUI_BORDER*2) {
  274. slider->knob -= _gluiX - x;
  275. _gluiX = x;
  276.     }
  277. } else {
  278.     /* clamp the incoming old position, or else the knob will
  279.                possibly "jump" due to the false delta. */
  280.     if (_gluiY < GLUI_BORDER+1)
  281. _gluiY = GLUI_BORDER+1;
  282.     if (_gluiY > slider->length - GLUI_BORDER*2)
  283. _gluiY = slider->length - GLUI_BORDER*2;
  284.     /* we don't want to take any action if the mouse pointer
  285.                has moved passed the extents of the slider. */
  286.     if (y > GLUI_BORDER && y < slider->length - GLUI_BORDER*2) {
  287. slider->knob -= _gluiY - y;
  288. _gluiY = y;
  289.     }
  290. }
  291. _gluiConstrainKnob(slider);
  292. /* post a display _before_ updating the user, so that the knob
  293.            won't lag behind. */
  294. glutPostRedisplay();
  295. /* make sure to set the parent window current, otherwise if
  296.            there is OpenGL state being changed in the update callback,
  297.            it will be done to the sliders context! */
  298. glutSetWindow(slider->parent);
  299. slider->update(_gluiKnobPercent(slider));
  300.     }
  301. }
  302. static void
  303. _gluiPassive(int x, int y)
  304. {
  305.     GLUIslider* slider = _gluiCurrentSlider();
  306.     _gluiConvertY(slider, &y);
  307.     if (_gluiHitKnob(slider, x, y) == 0)
  308. slider->lit = GL_TRUE;
  309.     else
  310. slider->lit = GL_FALSE;
  311.     glutPostRedisplay();
  312. }
  313. /* ARGSUSED */
  314. static void
  315. _gluiEntry(int state)
  316. {
  317.     GLUIslider* slider = _gluiCurrentSlider();
  318.     /* set the lit flag to false whether we are coming or going
  319.        because if we are doing either, we can't be on top of the knob!  */
  320.     slider->lit = GL_FALSE;
  321.     glutPostRedisplay();
  322. }
  323. void
  324. gluiReshape(int width, int height)
  325. {
  326.     float percent;
  327.     int x, y, w, h;
  328.     GLUIslider* slider = _gluiSliders;
  329.     while (slider) {
  330. /* we need to get the width and height of the parent, so set
  331.            it current. */
  332. glutSetWindow(slider->parent);
  333. /* all this mumbo jumbo takes care of the negative arguments
  334.            to attach the slider to different sides of the window. */
  335. x = slider->win_x;
  336. if (x < 0)
  337.     x = width - slider->win_w + x + 1;
  338. y = slider->win_y;
  339. if (y < 0)
  340.     y = height - slider->win_h + y + 1;
  341. w = slider->win_w;
  342. if (w < 0)
  343.     w = glutGet(GLUT_WINDOW_WIDTH) + slider->win_w - slider->win_x;
  344. h = slider->win_h;
  345. if (h < 0)
  346.     h = glutGet(GLUT_WINDOW_HEIGHT) + slider->win_h - slider->win_y;
  347. glutSetWindow(slider->window);
  348. glutPositionWindow(x, y);
  349. glutReshapeWindow(w, h);
  350.   percent = _gluiKnobPercent(slider);
  351. if (slider->type == GLUI_HORIZONTAL)
  352.     slider->length = w;
  353. else
  354.     slider->length = h;
  355. slider->knob = _gluiKnobPosition(slider, percent);
  356. _gluiConstrainKnob(slider);
  357. glViewport(0, 0, w, h);
  358. glMatrixMode(GL_PROJECTION);
  359. glLoadIdentity();
  360. gluOrtho2D(0, w, 0, h);
  361. glMatrixMode(GL_MODELVIEW);
  362. glLoadIdentity();
  363. slider = slider->next;
  364.     }
  365. }
  366. int
  367. gluiVerticalSlider(int parent, int x, int y, int width, int height,
  368.    float percent, void (*update)(float))
  369. {
  370.     GLUIslider* slider = (GLUIslider*)malloc(sizeof(GLUIslider));
  371.     slider->next = _gluiSliders;
  372.     _gluiSliders = slider;
  373.     slider->type = GLUI_VERTICAL;
  374.     slider->parent = parent;
  375.     slider->window = glutCreateSubWindow(parent, x, y, width, height);
  376.     slider->win_x = x;
  377.     slider->win_y = y;
  378.     slider->win_w = width;
  379.     slider->win_h = height;
  380.     slider->update = update;
  381.     slider->lit = GL_FALSE;
  382. /*     glutSetCursor(GLUT_CURSOR_LEFT_RIGHT); */
  383.     glutDisplayFunc(_gluiDisplay);
  384.     glutEntryFunc(_gluiEntry);
  385.     glutMouseFunc(_gluiMouse);
  386.     glutMotionFunc(_gluiMotion);
  387.     glutPassiveMotionFunc(_gluiPassive);
  388.     glDisable(GL_LIGHTING);
  389.     glDisable(GL_DEPTH_TEST);
  390.     slider->length = height;
  391.     if (height < 0) {
  392. glutSetWindow(parent);
  393. slider->length = glutGet(GLUT_WINDOW_HEIGHT) + height - slider->win_y;
  394.     }
  395.     slider->knob = _gluiKnobPosition(slider, percent);
  396.     _gluiConstrainKnob(slider);
  397.     return slider->window;
  398. }
  399. /* On a horizontal slider, the height must be non-negative. */
  400. int
  401. gluiHorizontalSlider(int parent, int x, int y, int width, int height,
  402.      float percent, void (*update)(float))
  403. {
  404.     GLUIslider* slider = (GLUIslider*)malloc(sizeof(GLUIslider));
  405.     slider->next = _gluiSliders;
  406.     _gluiSliders = slider;
  407.     slider->type = GLUI_HORIZONTAL;
  408.     slider->parent = parent;
  409.     slider->window = glutCreateSubWindow(parent, x, y, width, height);
  410.     slider->win_x = x;
  411.     slider->win_y = y;
  412.     slider->win_w = width;
  413.     slider->win_h = height;
  414.     slider->update = update;
  415.     slider->lit = GL_FALSE;
  416. /*     glutSetCursor(GLUT_CURSOR_LEFT_RIGHT); */
  417.     glutDisplayFunc(_gluiDisplay);
  418.     glutEntryFunc(_gluiEntry);
  419.     glutMouseFunc(_gluiMouse);
  420.     glutMotionFunc(_gluiMotion);
  421.     glutPassiveMotionFunc(_gluiPassive);
  422.     glDisable(GL_LIGHTING);
  423.     glDisable(GL_DEPTH_TEST);
  424.     slider->length = width;
  425.     if (width < 0) {
  426. glutSetWindow(parent);
  427. slider->length = glutGet(GLUT_WINDOW_WIDTH) + width - slider->win_x;
  428.     }
  429.     slider->knob = _gluiKnobPosition(slider, percent);
  430.     _gluiConstrainKnob(slider);
  431.     return slider->window;
  432. }