/* navigate2.c /* An example of a navigation and interaction. Navigation is added /* to interact.c (without the joystick control of scaling). The positions /* and vectors used for interaction must be converted to world coordinates. */ #include #include /* The data that will be shared between processes */ struct _balldata { float x,y,z; float radius; int grabbed; struct _balldata *next; }; void init_gl(void),draw_balls(struct _balldata **); void check_add(struct _balldata **list); struct _balldata * update_held(struct _balldata *ball); struct _balldata * check_grab(struct _balldata **list); void navigate(void); main(int argc,char **argv) { struct _balldata **ballList,*heldBall=NULL; CAVEConfigure(&argc,argv,NULL); ballList = (struct _balldata **) CAVEMalloc(sizeof(struct _balldata *)); *ballList = NULL; CAVEInit(); CAVEInitApplication(init_gl,0); CAVEDisplay(draw_balls,1,ballList); while (!CAVEgetbutton(CAVE_ESCKEY)) { navigate(); check_add(ballList); if (heldBall) heldBall = update_held(heldBall); else heldBall = check_grab(ballList); sginap(1); } CAVEExit(); } #define SPEED 5.0f /* Max navigation speed in feet per second */ /* navigate - perform the navigation calculations. */ void navigate(void) { float jx=CAVE_JOYSTICK_X,jy=CAVE_JOYSTICK_Y,dt,t; static float prevtime = 0; t = CAVEGetTime(); dt = t - prevtime; prevtime = t; if (fabs(jy)>0.2) { float wandFront[3]; CAVEGetVector(CAVE_WAND_FRONT,wandFront); CAVENavTranslate(wandFront[0]*jy*SPEED*dt, wandFront[1]*jy*SPEED*dt, wandFront[2]*jy*SPEED*dt); } if (fabs(jx)>0.2) CAVENavRot(-jx*90.0f*dt,'y'); } void check_add(struct _balldata **list) { if (CAVEButtonChange(3) == -1) { struct _balldata *ball; float wandPos[3],wandFront[3]; float wandWorldPos[3],wandWorldFront[3]; ball = (struct _balldata *) CAVEMalloc(sizeof(struct _balldata)); if (!ball) { fprintf(stderr,"OUT OF MEMORY!\n"); return; } CAVEGetPosition(CAVE_WAND,wandPos); CAVENavConvertCAVEToWorld(wandPos,wandWorldPos); CAVEGetVector(CAVE_WAND_FRONT,wandFront); CAVENavConvertVectorCAVEToWorld(wandFront,wandWorldFront); ball->x = wandWorldPos[0] + wandWorldFront[0]*2; ball->y = wandWorldPos[1] + wandWorldFront[1]*2; ball->z = wandWorldPos[2] + wandWorldFront[2]*2; ball->radius = 1; ball->grabbed = 0; ball->next = *list; *list = ball; } } struct _balldata * update_held(struct _balldata *ball) { if (!CAVEBUTTON1) { float wandPos[3],wandWorldPos[3]; CAVEGetPosition(CAVE_WAND,wandPos); CAVENavConvertCAVEToWorld(wandPos,wandWorldPos); ball->x = wandWorldPos[0]; ball->y = wandWorldPos[1]; ball->z = wandWorldPos[2]; ball->grabbed = 0; return NULL; } return ball; } struct _balldata * check_grab(struct _balldata **list) { if (CAVEButtonChange(1) == 1) { struct _balldata *ball; float wandPos[3],wandWorldPos[3]; CAVEGetPosition(CAVE_WAND,wandPos); CAVENavConvertCAVEToWorld(wandPos,wandWorldPos); for (ball = *list; ball; ball = ball->next) { float dist; #define SQR(x) ((x)*(x)) dist = SQR(ball->x - wandWorldPos[0]) + SQR(ball->y - wandWorldPos[1]) + SQR(ball->z - wandWorldPos[2]); if (dist < SQR(ball->radius)) { ball->grabbed = 1; return ball; } } } return NULL; } static GLUquadricObj *sphereObj; /* init_gl - initialize GL lighting & materials */ void init_gl(void) { float redMaterial[] = { .8, 0, .8, 1 }; glEnable(GL_LIGHT0); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, redMaterial); sphereObj = gluNewQuadric(); } /* draw_balls - draw the balls, using the shared data for their positions & sizes */ void draw_balls(struct _balldata **ballList) { struct _balldata *ball; glClearColor(0., 0., 0., 0.); glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT); glEnable(GL_LIGHTING); for (ball = *ballList; ball; ball = ball->next) /* Draw the grabbed ball in CAVE coordinates */ if (ball->grabbed) { glPushMatrix(); CAVEWandTransform(); gluSphere(sphereObj, ball->radius, 8, 8); glPopMatrix(); } /* Draw all the other balls in world coordinates */ else { glPushMatrix(); CAVENavTransform(); glTranslatef(ball->x, ball->y, ball->z); gluSphere(sphereObj, ball->radius, 4, 4); glPopMatrix(); } glDisable(GL_LIGHTING); }