glui.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:14k
- /*
- glui.c
- Nate Robins, 1997.
- OpenGL based user interface.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <GL/glut.h>
- #define GLUI_BORDER 3
- #define GLUI_KNOB 40
- #define GLUI_RAISED 1
- #define GLUI_SUNKEN 0
- #define GLUI_HORIZONTAL 0
- #define GLUI_VERTICAL 1
- #define GLUI_LESS -1
- #define GLUI_HIT 0
- #define GLUI_MORE 1
- #define GLUI_HILITE 0.15
- typedef struct _GLUIslider {
- int type; /* vertical/horizontal */
- int parent; /* parent of this slider */
- int window; /* this sliders window */
- int win_x; /* slider window x (parent relative) */
- int win_y; /* slider window y (parent relative) */
- int win_w; /* slider window width */
- int win_h; /* slider window height */
- int length; /* length of the slider in pixels */
- int knob; /* position of the knob in pixels */
- int lit; /* currently lit? */
- void (*update)(float); /* callback for updating (returns %) */
- struct _GLUIslider* next;
- } GLUIslider;
- static GLUIslider* _gluiSliders = NULL;
- static GLUIslider* _gluiHit = NULL;
- static GLUIslider*
- _gluiCurrentSlider(void)
- {
- GLUIslider* slider = _gluiSliders;
- int window = glutGetWindow();
- while(slider) {
- if (slider->window == window)
- break;
- slider = slider->next;
- }
- if (!slider)
- printf("glui: _gluiCurrentSlider() failed!n");
- return slider;
- }
- static void
- _gluiEmboss(int raised, int lit, int x, int y, int width, int height)
- {
- int i;
- float c;
- for (i = 0; i < GLUI_BORDER; i++) {
- c = (float)i / (GLUI_BORDER * 5) + (lit ? GLUI_HILITE : 0.0);
- if (raised)
- glColor3f(0.275+c, 0.2+c, 0.2+c);
- else
- glColor3f(0.875-c, 0.8-c, 0.8-c);
- glBegin(GL_LINE_STRIP);
- glVertex2f(x+i+1, y+i);
- glVertex2f(x+width-i-1, y+i);
- glVertex2f(x+width-i-1, y+height-i);
- glEnd();
- }
- for (i = 0; i < GLUI_BORDER; i++) {
- c = (float)i / (GLUI_BORDER * 5);
- if (raised)
- glColor3f(0.875-c, 0.8-c, 0.8-c);
- else
- glColor3f(0.275+c, 0.2+c, 0.2+c);
- glBegin(GL_LINE_STRIP);
- glVertex2f(x+i, y+i);
- glVertex2f(x+i, y+height-i-1);
- glVertex2f(x+width-i-1, y+height-i-1);
- glEnd();
- }
- c = lit ? GLUI_HILITE : 0.0;
- if (raised)
- glColor3f(0.575+c, 0.5+c, 0.5+c);
- else
- glColor3f(0.475+c, 0.3+c, 0.3+c);
- glRectf(x+i, y+i, x+width-i, y+height-i);
- }
- static void
- _gluiDisplay(void)
- {
- int lit;
- GLUIslider* slider = _gluiCurrentSlider();
- lit = slider->lit ? GLUI_HILITE : 0.0;
- glClear(GL_COLOR_BUFFER_BIT);
- if (slider->type == GLUI_HORIZONTAL) {
- _gluiEmboss(GLUI_SUNKEN, 0, /* never lit */
- 0, 0, slider->length, slider->win_h);
- _gluiEmboss(GLUI_RAISED, slider->lit,
- slider->knob - GLUI_KNOB/2, GLUI_BORDER,
- GLUI_KNOB + GLUI_BORDER, slider->win_h - GLUI_BORDER*2);
- /* XXX why is it GLUI_KNOB+GLUI_BORDER ? */
- glColor3f(0.975+lit, 0.9+lit, 0.9+lit);
- glBegin(GL_LINES);
- glVertex2f(slider->knob-2, GLUI_BORDER*2-1);
- glVertex2f(slider->knob-2, slider->win_h-GLUI_BORDER*2+1);
- glVertex2f(slider->knob+1, GLUI_BORDER*2-1);
- glVertex2f(slider->knob+1, slider->win_h-GLUI_BORDER*2+1);
- glVertex2f(slider->knob+4, GLUI_BORDER*2-1);
- glVertex2f(slider->knob+4, slider->win_h-GLUI_BORDER*2+1);
- glEnd();
- glColor3f(0.175+lit, 0.1+lit, 0.1+lit);
- glBegin(GL_LINES);
- glVertex2f(slider->knob-3, GLUI_BORDER*2-1);
- glVertex2f(slider->knob-3, slider->win_h-GLUI_BORDER*2+1);
- glVertex2f(slider->knob+0, GLUI_BORDER*2-1);
- glVertex2f(slider->knob+0, slider->win_h-GLUI_BORDER*2+1);
- glVertex2f(slider->knob+3, GLUI_BORDER*2-1);
- glVertex2f(slider->knob+3, slider->win_h-GLUI_BORDER*2+1);
- glEnd();
- } else {
- _gluiEmboss(GLUI_SUNKEN, 0, /* never lit */
- 0, 0, slider->win_w, slider->length);
- _gluiEmboss(GLUI_RAISED, slider->lit,
- GLUI_BORDER, slider->knob - GLUI_KNOB/2,
- slider->win_w - GLUI_BORDER*2, GLUI_KNOB + GLUI_BORDER);
- /* XXX why is it GLUI_KNOB+GLUI_BORDER ? */
- glColor3f(0.175+lit, 0.1+lit, 0.1+lit);
- glBegin(GL_LINES);
- glVertex2f(GLUI_BORDER*2-1, slider->knob-2);
- glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob-2);
- glVertex2f(GLUI_BORDER*2-1, slider->knob+1);
- glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob+1);
- glVertex2f(GLUI_BORDER*2-1, slider->knob+4);
- glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob+4);
- glEnd();
- glColor3f(0.975+lit, 0.9+lit, 0.9+lit);
- glBegin(GL_LINES);
- glVertex2f(GLUI_BORDER*2-1, slider->knob-3);
- glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob-3);
- glVertex2f(GLUI_BORDER*2-1, slider->knob+0);
- glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob+0);
- glVertex2f(GLUI_BORDER*2-1, slider->knob+3);
- glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob+3);
- glEnd();
- }
- glutSwapBuffers();
- }
- static int
- _gluiHitKnob(GLUIslider* slider, int x, int y)
- {
- if (slider->type == GLUI_HORIZONTAL) {
- /* we know that we don't have to test the y coordinate because
- the mouse came down in the window (this means that they can
- hit the borders and still move the knob, but that's okay).
- */
- if (x > slider->knob - GLUI_KNOB/2 && x < slider->knob + GLUI_KNOB/2)
- return GLUI_HIT;
- else if (x < slider->knob)
- return GLUI_LESS;
- else
- return GLUI_MORE;
- } else {
- /* we know that we don't have to test the x coordinate because
- the mouse came down in the window (this means that they can
- hit the borders and still move the knob, but that's okay).
- */
- if (y > slider->knob - GLUI_KNOB/2 && y < slider->knob + GLUI_KNOB/2)
- return GLUI_HIT;
- else if (y < slider->knob)
- return GLUI_LESS;
- else
- return GLUI_MORE;
- }
- }
- static void
- _gluiConstrainKnob(GLUIslider* slider)
- {
- if (slider->knob > slider->length - GLUI_BORDER*2 - GLUI_KNOB/2)
- slider->knob = slider->length - GLUI_BORDER*2 - GLUI_KNOB/2;
- else if (slider->knob < GLUI_BORDER + GLUI_KNOB/2)
- slider->knob = GLUI_BORDER + GLUI_KNOB/2;
- }
- static float
- _gluiKnobPercent(GLUIslider* slider)
- {
- return (float)(slider->knob - GLUI_KNOB/2 - GLUI_BORDER) /
- (slider->length - GLUI_BORDER*3 - GLUI_KNOB);
- }
- static int
- _gluiKnobPosition(GLUIslider* slider, float percent)
- {
- return GLUI_BORDER + GLUI_KNOB/2 + percent *
- (slider->length - GLUI_BORDER*3 - GLUI_KNOB);
- }
- static int _gluiX;
- static int _gluiY;
- static int _gluiMouseDown;
- static void
- _gluiTimer(int value)
- {
- GLUIslider* slider = (GLUIslider*)value;
- float percent;
- percent = _gluiKnobPercent(slider);
- if (_gluiMouseDown != 0 && percent > 0.0 && percent < 1.0) {
- if (_gluiMouseDown == GLUI_LESS) {
- slider->knob -= slider->length / 25.0;
- _gluiConstrainKnob(slider);
- } else {
- slider->knob += slider->length / 25.0;
- _gluiConstrainKnob(slider);
- }
- glutSetWindow(slider->window);
- glutPostRedisplay();
- slider->update(_gluiKnobPercent(slider));
- glutTimerFunc(20, _gluiTimer, (int)slider);
- }
- }
- static void
- _gluiConvertY(GLUIslider* slider, int* y)
- {
- if (slider->win_h < 0) {
- glutSetWindow(slider->parent);
- *y = glutGet(GLUT_WINDOW_HEIGHT) + slider->win_h - slider->win_y - *y;
- glutSetWindow(slider->window);
- } else {
- *y = slider->win_h - *y;
- }
- }
- /* ARGSUSED */
- static void
- _gluiMouse(int button, int state, int x, int y)
- {
- GLUIslider* slider = _gluiCurrentSlider();
- int side;
- _gluiConvertY(slider, &y);
- _gluiX = x;
- _gluiY = y;
- _gluiHit = NULL;
- _gluiMouseDown = GL_FALSE;
- if (state == GLUT_DOWN) {
- side = _gluiHitKnob(slider, x, y);
- if (side == GLUI_HIT) {
- _gluiHit = slider;
- } else if (side == GLUI_LESS) {
- slider->knob -= slider->length / 25.0;
- _gluiConstrainKnob(slider);
- } else {
- slider->knob += slider->length / 25.0;
- _gluiConstrainKnob(slider);
- }
- glutPostRedisplay();
- slider->update(_gluiKnobPercent(slider));
- _gluiMouseDown = side;
- if (side != 0) {
- glutTimerFunc(500, _gluiTimer, (int)slider);
- }
- } else {
- slider->lit = GL_FALSE;
- }
- }
- static void
- _gluiMotion(int x, int y)
- {
- GLUIslider* slider = _gluiHit;
- if (slider) {
- _gluiConvertY(slider, &y);
- if (slider->type == GLUI_HORIZONTAL) {
- /* clamp the incoming old position, or else the knob will
- possibly "jump" due to the false delta. */
- if (_gluiX < GLUI_BORDER+1)
- _gluiX = GLUI_BORDER+1;
- if (_gluiX > slider->length - GLUI_BORDER*2)
- _gluiX = slider->length - GLUI_BORDER*2;
- /* we don't want to take any action if the mouse pointer
- has moved passed the extents of the slider. */
- if (x > GLUI_BORDER && x < slider->length - GLUI_BORDER*2) {
- slider->knob -= _gluiX - x;
- _gluiX = x;
- }
- } else {
- /* clamp the incoming old position, or else the knob will
- possibly "jump" due to the false delta. */
- if (_gluiY < GLUI_BORDER+1)
- _gluiY = GLUI_BORDER+1;
- if (_gluiY > slider->length - GLUI_BORDER*2)
- _gluiY = slider->length - GLUI_BORDER*2;
- /* we don't want to take any action if the mouse pointer
- has moved passed the extents of the slider. */
- if (y > GLUI_BORDER && y < slider->length - GLUI_BORDER*2) {
- slider->knob -= _gluiY - y;
- _gluiY = y;
- }
- }
- _gluiConstrainKnob(slider);
- /* post a display _before_ updating the user, so that the knob
- won't lag behind. */
- glutPostRedisplay();
- /* make sure to set the parent window current, otherwise if
- there is OpenGL state being changed in the update callback,
- it will be done to the sliders context! */
- glutSetWindow(slider->parent);
- slider->update(_gluiKnobPercent(slider));
- }
- }
- static void
- _gluiPassive(int x, int y)
- {
- GLUIslider* slider = _gluiCurrentSlider();
- _gluiConvertY(slider, &y);
- if (_gluiHitKnob(slider, x, y) == 0)
- slider->lit = GL_TRUE;
- else
- slider->lit = GL_FALSE;
- glutPostRedisplay();
- }
- /* ARGSUSED */
- static void
- _gluiEntry(int state)
- {
- GLUIslider* slider = _gluiCurrentSlider();
- /* set the lit flag to false whether we are coming or going
- because if we are doing either, we can't be on top of the knob! */
- slider->lit = GL_FALSE;
- glutPostRedisplay();
- }
- void
- gluiReshape(int width, int height)
- {
- float percent;
- int x, y, w, h;
- GLUIslider* slider = _gluiSliders;
- while (slider) {
- /* we need to get the width and height of the parent, so set
- it current. */
- glutSetWindow(slider->parent);
- /* all this mumbo jumbo takes care of the negative arguments
- to attach the slider to different sides of the window. */
- x = slider->win_x;
- if (x < 0)
- x = width - slider->win_w + x + 1;
- y = slider->win_y;
- if (y < 0)
- y = height - slider->win_h + y + 1;
- w = slider->win_w;
- if (w < 0)
- w = glutGet(GLUT_WINDOW_WIDTH) + slider->win_w - slider->win_x;
- h = slider->win_h;
- if (h < 0)
- h = glutGet(GLUT_WINDOW_HEIGHT) + slider->win_h - slider->win_y;
- glutSetWindow(slider->window);
- glutPositionWindow(x, y);
- glutReshapeWindow(w, h);
- percent = _gluiKnobPercent(slider);
- if (slider->type == GLUI_HORIZONTAL)
- slider->length = w;
- else
- slider->length = h;
- slider->knob = _gluiKnobPosition(slider, percent);
- _gluiConstrainKnob(slider);
- glViewport(0, 0, w, h);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluOrtho2D(0, w, 0, h);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- slider = slider->next;
- }
- }
- int
- gluiVerticalSlider(int parent, int x, int y, int width, int height,
- float percent, void (*update)(float))
- {
- GLUIslider* slider = (GLUIslider*)malloc(sizeof(GLUIslider));
- slider->next = _gluiSliders;
- _gluiSliders = slider;
- slider->type = GLUI_VERTICAL;
- slider->parent = parent;
- slider->window = glutCreateSubWindow(parent, x, y, width, height);
- slider->win_x = x;
- slider->win_y = y;
- slider->win_w = width;
- slider->win_h = height;
- slider->update = update;
- slider->lit = GL_FALSE;
- /* glutSetCursor(GLUT_CURSOR_LEFT_RIGHT); */
- glutDisplayFunc(_gluiDisplay);
- glutEntryFunc(_gluiEntry);
- glutMouseFunc(_gluiMouse);
- glutMotionFunc(_gluiMotion);
- glutPassiveMotionFunc(_gluiPassive);
- glDisable(GL_LIGHTING);
- glDisable(GL_DEPTH_TEST);
- slider->length = height;
- if (height < 0) {
- glutSetWindow(parent);
- slider->length = glutGet(GLUT_WINDOW_HEIGHT) + height - slider->win_y;
- }
- slider->knob = _gluiKnobPosition(slider, percent);
- _gluiConstrainKnob(slider);
- return slider->window;
- }
- /* On a horizontal slider, the height must be non-negative. */
- int
- gluiHorizontalSlider(int parent, int x, int y, int width, int height,
- float percent, void (*update)(float))
- {
- GLUIslider* slider = (GLUIslider*)malloc(sizeof(GLUIslider));
- slider->next = _gluiSliders;
- _gluiSliders = slider;
- slider->type = GLUI_HORIZONTAL;
- slider->parent = parent;
- slider->window = glutCreateSubWindow(parent, x, y, width, height);
- slider->win_x = x;
- slider->win_y = y;
- slider->win_w = width;
- slider->win_h = height;
- slider->update = update;
- slider->lit = GL_FALSE;
- /* glutSetCursor(GLUT_CURSOR_LEFT_RIGHT); */
- glutDisplayFunc(_gluiDisplay);
- glutEntryFunc(_gluiEntry);
- glutMouseFunc(_gluiMouse);
- glutMotionFunc(_gluiMotion);
- glutPassiveMotionFunc(_gluiPassive);
- glDisable(GL_LIGHTING);
- glDisable(GL_DEPTH_TEST);
- slider->length = width;
- if (width < 0) {
- glutSetWindow(parent);
- slider->length = glutGet(GLUT_WINDOW_WIDTH) + width - slider->win_x;
- }
- slider->knob = _gluiKnobPosition(slider, percent);
- _gluiConstrainKnob(slider);
- return slider->window;
- }