This page was last updated: 9/10/03
#include <stdio.h> #include <math.h> #include <GL/gl.h> #include <GL/glu.h> #include <GL/glut.h> #include <GL/glui.h> #ifdef WIN32 #include <windows.h> const float M_PI = { 3.14159265 }; #endif
The Mouse Button callback gets called with the button that was moved, whether it went up or down, and the x and y coordinate of the mouse when it happened. The y coordinate is with respect to the top of the window, not the bottom.) Generally, you simply keep track of the state of the buttons and return. If you are doing any sort of picking, you figure out here what has been picked, so that the Mouse Motion callback can change the proper thing.
void
MouseButton(
int button, /* GLUT_*_BUTTON */
int state, /* GLUT_UP or GLUT_DOWN */
int x, int y /* where mouse was when button hit */
)
{
int b; /* LEFT, MIDDLE, or RIGHT */
int vdx, vdy; /* size of window */
vdx = glutGet( GLUT_WINDOW_WIDTH );
vdy = glutGet( GLUT_WINDOW_HEIGHT );
/* get the proper button bit mask: */
switch( button )
{
case GLUT_LEFT_BUTTON:
b = LEFT; break;
case GLUT_MIDDLE_BUTTON:
b = MIDDLE; break;
case GLUT_RIGHT_BUTTON:
b = RIGHT; break;
default:
b = 0;
fprintf( stderr, "Unknown mouse button: %d\n", button );
}
/* button down sets the bit, up clears the bit: */
if( state == GLUT_DOWN )
{
ActiveButton |= b; /* set the proper bit */
}
else
{
ActiveButton &= ~b; /* clear the proper bit */
}
}
The Mouse Motion callback is called with the new mouse coordinates after the movement occured. The y coordinate is with respect to the top of the window, not the bottom.) If you have already picked something, you can use this information to change it.
void
MouseMotion( int x, int y )
{
int vdx, vdy; /* size of window */
vdx = glutGet( GLUT_WINDOW_WIDTH );
vdy = glutGet( GLUT_WINDOW_HEIGHT );
y = vdy - y;
if( ActiveButton & LEFT )
{
. . .
}
. . .
glutSetWindow( TopWindow );
glutPostRedisplay();
}
You setup the menu structures in InitGraphics()
SegMenu = glutCreateMenu( DoSegMenu );
glutAddMenuEntry( "Large", FINE );
glutAddMenuEntry( "Small", CRUDE );
CurveMenu = glutCreateMenu( DoCurveMenu );
glutAddMenuEntry( "Bezier", BEZIER );
glutAddMenuEntry( "Fitted", CUBIC );
glutAddMenuEntry( "Parabloic Blend", PARABOLIC_BLEND );
ParabolaMenu = glutCreateMenu( DoParabolaMenu );
glutAddMenuEntry( "Off", FALSE );
glutAddMenuEntry( "On", TRUE );
/* initialize the pop-up menus: */
MainMenu = glutCreateMenu( DoMainMenu );
glutAddSubMenu( "Curve Type", CurveMenu );
glutAddSubMenu( "# of Line Segments", SegMenu );
glutAddSubMenu( "Sub-Parabolas", ParabolaMenu );
glutAddMenuEntry( "Quit", QUIT );
/* attach the pop-up menu to the right mouse button: */
glutAttachMenu( GLUT_RIGHT_BUTTON );
This defines the menus and specifies that the right button will pop them up. All those calls to glutCreateMenu() declare a callback routine to handle this menu. The callback routine will be given the second argument from the glutAddMenuEntry that was selected. It is up to your callback routine to do the right thing with it and then post a redisplay:
/* # line segments to use for the curve: */
#define FINE 50
#define CRUDE 15
/* curve types: */
#define BEZIER 0
#define CUBIC 1
#define PARABOLIC_BLEND 2
/* global variables: */
int CurveType; /* CUBIC, BEZIER, PARABOLIC_BLEND */
int NSegments; /* # line segments */
int ActiveButton; /* current button that is down */
int CurveMenu; /* id of the curve pop-up menu */
int MainMenu; /* id of the main pop-up menu */
int ParabolaMenu; /* id of the parabola pop-up menu */
int SegMenu; /* id of the segment pop-up menu */
void DoCurveMenu( int );
void DoMainMenu( int );
void DoParabolaMenu( int );
void DoSegMenu( int );
void
DoCurveMenu( int value )
{
CurveType = value;
glutSetWindow( TopWindow );
glutPostRedisplay();
}
void
DoMainMenu( int value )
{
switch( value )
{
case RESET:
Reset();
break;
case QUIT:
Quit();
break; /* never returns -- "don't need to do this" */
}
}
void
DoSegMenu( int value )
{
NSegments = value;
glutSetWindow( TopWindow );
glutPostRedisplay();
}