CAVELib Sample Program 2
Previous  Top  Next


This example draws a yellow grid pattern on the floor. It has red and blue bouncing spheres, and the user is able to navigate about the environment simply by pointing in the direction they wish to go and pressing the wand's joystick.

/* navigate1_mt.c
An example of navigating in a CAVE environment. The world is that
of bounce.c. The user navigates using the wand joystick - JOYSTICK_Y
controls the forward/back motion; JOYSTICK_X controls turning.
*/

#include <cave_ogl.h>
#include <GL/glu.h>
#ifndef WIN32
#include <strings.h>
#endif

#define SPEED 5.0f /* Max navigation speed in feet per second */


/* Values used for drawing a grid for the ground */
#define N 50
#define INCGRID 5


/* The data that will be shared between processes */
typedef struct spheredata {

float y;  
 
}SPHEREDATA;

/* Global pointer to shared memory */
SPHEREDATA* sphere;

#ifndef CAVE_THREAD
static GLuint redMat, blueMat; 
static GLUquadricObj *sphereObj;
#else
static GLuint redMat[CAVE_MAX_WALLS], blueMat[CAVE_MAX_WALLS]; 
static GLUquadricObj *sphereObj[CAVE_MAX_WALLS];
#endif

/* function prototypes */
void initGL(void);
void drawSpheres(void);
void drawGround(void);
void initSphereMem(void);
void frameUpdate(void);
void compute(void);
void navigate(void);void

int main(int argc,char **argv) {

CAVEConfigure(&argc,argv,NULL);  
 
/* Initialize sphere memory */  
initSphereMem();  
CAVEInitApplication(initGL,0);  
 
/* Give the library a pointer to the drawing function */  
CAVEDisplay((CAVECALLBACK)drawSpheres,0);  
 
/* Give the library a pointer to an update function */  
CAVEFrameFunction((CAVECALLBACK)frameUpdate,0);  
 
CAVEInit();  
 
while (!CAVEgetbutton(CAVE_ESCKEY) && !CAVESync->Quit) {  
 
/* Nap in the while loop if not doing any processing,  
cuts down on needless looping   
*/  
CAVEUSleep(10);  
 
}  
CAVEExit();   
 
}

/* initSphereMem - initializes sphere memory. The data is allocated from a
main memory arena, and will be common to all display threads. 
*/
void initSphereMem() {

sphere = (SPHEREDATA*) malloc(2*sizeof(SPHEREDATA));  
#ifndef WIN32  
bzero(sphere,2*sizeof(SPHEREDATA));  
#else  
memset(sphere,0,2*sizeof(SPHEREDATA));  
#endif  
 
}

/* frameUpdate - do the computation of the sphere in the frame update so
it's data values are synced with the draw function. Since the data
is shared we only need to update the spheres position once per frame,
hence the if(CAVEMasterDisplay()) test, this guarantees it only gets
executed once per frame regardless of the number of processes.
*/
void frameUpdate() {

if(CAVEMasterDisplay()) {  
 
compute();  
navigate();  
 
}  
CAVEDisplayBarrier();  
 
}

/* compute - compute new positions for the spheres. The height of the spheres
is a function of the current CAVE time.
*/
void compute() {

float t = *CAVETime;  
sphere[0].y = (float) fabs(sin(t)) * 6 + 1;  
sphere[1].y = (float) fabs(sin(t)) * 4 + 1;  
 
}

/* navigate - perform the navigation calculations. This checks the joystick
state and uses that to move and rotate. The Y position of the joystick
determines the speed of motion in the direction of the wand. The X position
of the joystick determines the speed of rotation about the CAVE's Y axis.
Joystick values in the range -.2 to .2 are ignored; this provides a dead
zone to eliminate noise. The motion is scaled by dt, the time passed since
the last call to navigate(), in order to maintain a smooth speed 
irrespective of speed of rendering.
*/
void navigate(void) {

float jx, jy, dt, t;  
static float prevtime = 0;  
 
if(CAVEMasterDisplay()) {  
 
jx=CAVE_JOYSTICK_X;  
jy=CAVE_JOYSTICK_Y;  
t = (float) 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');  
 
}  
 
}  
 
}

/* initGL - initialize GL lighting & materials */
void initGL(void) {

float redMaterial[] = { 1, 0, 0, 1 };  
float blueMaterial[] = { 0, 0, 1, 1 };  
 
/* Enable light 0*/  
glEnable(GL_LIGHT0);  
 
/* Create a thread unique display list for the red and   
then the blue material   
*/  
redMat[CAVEUniqueIndex()] = glGenLists(1);  
glNewList(redMat[CAVEUniqueIndex()], GL_COMPILE);  
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, redMaterial);  
glEndList();  
blueMat[CAVEUniqueIndex()] = glGenLists(1);  
glNewList(blueMat[CAVEUniqueIndex()], GL_COMPILE);  
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blueMaterial);  
glEndList();  
 
/* Make a new quadric to draw a sphere */  
sphereObj[CAVEUniqueIndex()] = gluNewQuadric();  
 
}

/* drawSpheres - draw the two spheres, using the shared data for their
y coordinates 
*/
void drawSpheres() {

 
/* Clear the screen and zbuffer */  
glClearColor(0., 0., 0., 0.);  
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);  
 
glEnable(GL_LIGHTING);  
 
/* Apply the navigation transformation */  
CAVENavTransform();  
 
/* Activate the Red Material and draw a red sphere */  
glCallList(redMat[CAVEUniqueIndex()]);  
glPushMatrix();  
glTranslatef(2.0, sphere[0].y, -5.0);  
gluSphere(sphereObj[CAVEUniqueIndex()], 1.0, 8, 8);  
glPopMatrix();  
 
/* Activate the Blue Material and draw a blue sphere */  
glCallList(blueMat[CAVEUniqueIndex()]);  
glPushMatrix();  
glTranslatef(-2.0, sphere[1].y, -5.0);  
gluSphere(sphereObj[CAVEUniqueIndex()], 1.0, 8, 8);  
glPopMatrix();  
glDisable(GL_LIGHTING);  
drawGround();  
 
}

void drawGround(void) {

int x;  
float pt[3];  
 
glColor3ub(255, 255, 0);  
for (x = -N; x <= N; x+=INCGRID) {  
 
glBegin(GL_LINE_STRIP);  
pt[0] = x; pt[1] = 0.0; pt[2] = -N;  
glVertex3fv(pt);  
pt[0] = x; pt[1] = 0.0; pt[2] = N;  
glVertex3fv(pt);  
glEnd();  
 
glBegin(GL_LINE_STRIP);  
pt[0] = -N; pt[1] = 0.0; pt[2] = x;  
glVertex3fv(pt);  
pt[0] = N; pt[1] = 0.0; pt[2] = x;  
glVertex3fv(pt);  
glEnd();  
 
}  
}