/***********************************************************************/ /***********************************************************************/ /* FreeVR OpenGL tutorial example 10: ex10_manip.c */ /* FreeVR OpenGL tutorial example 11: ex11_locks.c */ /* Last tested with: FreeVR version 0.6a */ /* Last tested with: FreeVR version 0.6a */ /* Last Modified: July 19, 2004 */ /* Last Modified: September 26, 2003 */ /* URL: http://freevr.org */ /* URL: http://freevr.org */ /***********************************************************************/ /***********************************************************************/ /* This example code demonstrates a VR application program that */ /* This example code re-demonstrates the VR application program that */ /* allows the user to grab an object and translate it. Selection */ /* allows the user to grab an object and translate it. We now add */ /* method is via direct contact with the wand. */ /* locking code, to remove the potential for bugs that can occur */ /* when one process is writing to the same memory from which another */ /* is simultaneously reading. */ /* */ /* */ /* */ /* */ /* The new features of this example include: */ /* The new features of this example include: */ /* - FreeVR Library functions, variables, and macros: */ /* - FreeVR Library functions, variables, and macros: */ /* * vrLockCreate(); */ /* * vrLockWriteSet(); */ /* * vrLockWriteRelease(); */ /* * vrLockReadSet(); */ /* * vrLockReadRelease(); */ /* */ /* */ /* Considerations: */ /* Considerations: */ /* - since we now grab objects with the wand, the simple button */ /* - Locks help avoid contentions between attempts to read from or */ /* presses to move the green pyramid are removed. */ /* write to memory to which another process is writing. */ /* - It is important to make sure locks are released after each use. */ /* - Due to the time now spent waiting in locks, time-related factors*/ /* that are not explicitly correlated with the passage of */ /* simulation time may require readjustment. */ /* */ /* */ /* This application uses the files: */ /* This application uses the files: */ /* - shapes.c (Bill Sherman's simple OpenGL shapes) */ /* - shapes.c (Bill Sherman's simple OpenGL shapes) */ /* */ /* */ /* Copyright 2010, William R. Sherman, All Rights Reserved. */ /* Copyright 2010, William R. Sherman, All Rights Reserved. */ /* In particular, the right to republish this file in whole or in */ /* In particular, the right to republish this file in whole or in */ /* part, in any form (including electronic forms) is prohibited */ /* part, in any form (including electronic forms) is prohibited */ /* without written consent of the copyright holder. */ /* without written consent of the copyright holder. */ /***********************************************************************/ /***********************************************************************/ #include <stdio.h> /* needed for printf(), etc. */ #include <stdio.h> /* needed for printf(), etc. */ #include <stdlib.h> /* needed for exit() */ #include <stdlib.h> /* needed for exit() */ #include <signal.h> /* needed for signal() and its arguments */ #include <signal.h> /* needed for signal() and its arguments */ #include <unistd.h> /* not sure why/whether this is needed */ #include <unistd.h> /* not sure why/whether this is needed */ #include <math.h> /* needed for fabs() & copysign() */ #include <math.h> /* needed for fabs() & copysign() */ #include <GL/gl.h> /* needed for all OpenGL functions & values */ #include <GL/gl.h> /* needed for all OpenGL functions & values */ #include "freevr.h" /* needed for FreeVR functions & values */ #include "freevr.h" /* needed for FreeVR functions & values */ #define WAND_SENSOR 1 /* TODO: this should really be based on the c #define WAND_SENSOR 1 /* TODO: this should really be based on the c /* Define a structure for information about each individual object. */ /* Define a structure for information about each individual object. */ typedef struct { typedef struct { float x, y, z; /* location o float x, y, z; /* location o GLubyte color[3]; /* color of t GLubyte color[3]; /* color of t enum { cube,pyramid,ud_pyramid }shape; /* shape of t enum { cube,pyramid,ud_pyramid }shape; /* shape of t } ObjectType; } ObjectType; /* Define a structure for holding a database of the virtual world. */ /* Define a structure for holding a database of the virtual world. */ typedef struct { typedef struct { int number_of_objects; /* number of int number_of_objects; /* number of int selected_object; /* currently int selected_object; /* currently ObjectType object[3]; /* array of o ObjectType object[3]; /* array of o vrLock lock; /* to avoid b } WorldDataType; } WorldDataType; /**************************************************************************** /**************************************************************************** /* These function declarations are very important -- they will be used as arg /* These function declarations are very important -- they will be used as arg void exit_application(int signal); /* cleanly close down operati void exit_application(int signal); /* cleanly close down operati void init_gfx(void); /* initialize the graphics void init_gfx(void); /* initialize the graphics void draw_world(WorldDataType *wd, vrRenderInfo *rendinfo); /* render the void draw_world(WorldDataType *wd, vrRenderInfo *rendinfo); /* render the void init_world(WorldDataType *wd); /* initialize the world param void init_world(WorldDataType *wd); /* initialize the world param void update_world(WorldDataType *wd); /* perform the world simulati void update_world(WorldDataType *wd); /* perform the world simulati /***********************************************************************/ /***********************************************************************/ main(int argc, char* argv[]) main(int argc, char* argv[]) { { WorldDataType *wd; WorldDataType *wd; /**********************************/ /**********************************/ /*** initialize FreeVR routines ***/ /*** initialize FreeVR routines ***/ /**********************************/ /**********************************/ signal(SIGINT, SIG_IGN); signal(SIGINT, SIG_IGN); vrConfigure(&argc, argv, NULL); /* allow CLAs to affect confi vrConfigure(&argc, argv, NULL); /* allow CLAs to affect confi vrStart(); vrStart(); signal(SIGINT, exit_application); signal(SIGINT, exit_application); /********************/ /********************/ /* create the world */ /* create the world */ wd = (WorldDataType *)vrShmemAlloc0(sizeof(WorldDataType)); wd = (WorldDataType *)vrShmemAlloc0(sizeof(WorldDataType)); wd->lock = vrLockCreate(); init_world(wd); init_world(wd); /***************************************/ /***************************************/ /* set up the FreeVR library functions */ /* set up the FreeVR library functions */ vrFunctionSetCallback(VRFUNC_DISPLAY_INIT, vrCallbackCreate(init_gfx, vrFunctionSetCallback(VRFUNC_DISPLAY_INIT, vrCallbackCreate(init_gfx, vrFunctionSetCallback(VRFUNC_DISPLAY, vrCallbackCreate(draw_world, 1, vrFunctionSetCallback(VRFUNC_DISPLAY, vrCallbackCreate(draw_world, 1, /********************************************************/ /********************************************************/ /* define the application name, authors, controls, etc. */ /* define the application name, authors, controls, etc. */ vrSystemSetName("example 10 -- manipulation"); vrSystemSetName("example 11 -- locks"); vrSystemSetAuthors("Bill Sherman"); vrSystemSetAuthors("Bill Sherman"); vrSystemSetExtraInfo("An example to demonstrate direct manipulation o vrSystemSetExtraInfo("An example to demonstrate the use of locks to k vrSystemSetStatusDescription("Application running fine"); vrSystemSetStatusDescription("Application running fine"); vrInputSet2switchDescription(0, "Terminate the application"); vrInputSet2switchDescription(0, "Terminate the application"); vrInputSet2switchDescription(1, "Move the selected object"); vrInputSet2switchDescription(1, "Move the selected object"); vrInputSetValuatorDescription(0, "Move the green pyramid in the Z-pla vrInputSetValuatorDescription(0, "Move the green pyramid in the Z-pla vrInputSetValuatorDescription(1, "Move the green pyramid in the X-pla vrInputSetValuatorDescription(1, "Move the green pyramid in the X-pla vrInputSet6sensorDescription(WAND_SENSOR, "Move a short cyan pointer vrInputSet6sensorDescription(WAND_SENSOR, "Move a short cyan pointer /***************************/ /***************************/ /*** do world simulation ***/ /*** do world simulation ***/ /***************************/ /***************************/ /* run until terminate key is pressed (Escape by default) */ /* run until terminate key is pressed (Escape by default) */ while(!vrGet2switchValue(0)) { while(!vrGet2switchValue(0)) { vrFrame(); vrFrame(); update_world(wd); update_world(wd); } } /*********************/ /*********************/ /*** close up shop ***/ /*** close up shop ***/ /*********************/ /*********************/ exit_application(0); exit_application(0); } } /********************************************************************/ /********************************************************************/ /* exit_application(): clean up anything started by the application */ /* exit_application(): clean up anything started by the application */ /* (forked processes, open files, open sockets, etc.) */ /* (forked processes, open files, open sockets, etc.) */ /********************************************************************/ /********************************************************************/ void exit_application(int signal) void exit_application(int signal) { { vrExit(); vrExit(); exit(0); exit(0); } } /* ----------------8<-----------------8<-----------------8<----------------*/ /* ----------------8<-----------------8<-----------------8<----------------*/ /* In a non-example applicatation, the following would be a separate file. */ /* In a non-example applicatation, the following would be a separate file. */ /**********************************/ /**********************************/ /**********************************/ /**********************************/ /** The World Simulation section **/ /** The World Simulation section **/ /**********************************/ /**********************************/ /**********************************/ /**********************************/ /**************************************************************/ /**************************************************************/ /* init_world(): create the initial conditions of the dynamic */ /* init_world(): create the initial conditions of the dynamic */ /* simulation. */ /* simulation. */ /**************************************************************/ /**************************************************************/ void init_world(WorldDataType *wd) void init_world(WorldDataType *wd) { { int objnum = 0; int objnum = 0; vrLockWriteSet(wd->lock); /* object 1 - a blue cube */ /* object 1 - a blue cube */ wd->object[objnum].shape = cube; wd->object[objnum].shape = cube; wd->object[objnum].color[0] = 100; wd->object[objnum].color[0] = 100; wd->object[objnum].color[1] = 100; wd->object[objnum].color[1] = 100; wd->object[objnum].color[2] = 255; wd->object[objnum].color[2] = 255; wd->object[objnum].x = 0.0; wd->object[objnum].x = 0.0; wd->object[objnum].y = 5.0; wd->object[objnum].y = 5.0; wd->object[objnum].z = -4.0; wd->object[objnum].z = -4.0; objnum++; objnum++; /* object 2 - a red pyramid */ /* object 2 - a red pyramid */ wd->object[objnum].shape = pyramid; wd->object[objnum].shape = pyramid; wd->object[objnum].color[0] = 255; wd->object[objnum].color[0] = 255; wd->object[objnum].color[1] = 100; wd->object[objnum].color[1] = 100; wd->object[objnum].color[2] = 100; wd->object[objnum].color[2] = 100; wd->object[objnum].x = -4.0; wd->object[objnum].x = -4.0; wd->object[objnum].y = 5.0; wd->object[objnum].y = 5.0; wd->object[objnum].z = -4.0; wd->object[objnum].z = -4.0; objnum++; objnum++; /* object 3 - an upside-down green pyramid */ /* object 3 - an upside-down green pyramid */ wd->object[objnum].shape = ud_pyramid; wd->object[objnum].shape = ud_pyramid; wd->object[objnum].color[0] = 100; wd->object[objnum].color[0] = 100; wd->object[objnum].color[1] = 255; wd->object[objnum].color[1] = 255; wd->object[objnum].color[2] = 100; wd->object[objnum].color[2] = 100; wd->object[objnum].x = 4.0; wd->object[objnum].x = 4.0; wd->object[objnum].y = 5.0; wd->object[objnum].y = 5.0; wd->object[objnum].z = -4.0; wd->object[objnum].z = -4.0; objnum++; objnum++; wd->number_of_objects = objnum; wd->number_of_objects = objnum; wd->selected_object = -1; wd->selected_object = -1; vrLockWriteRelease(wd->lock); } } /*********************************************************************/ /*********************************************************************/ /* update_world(): In this version, we handle the user interactions. */ /* update_world(): In this version, we handle the user interactions. */ /* Both selecting, and moving the selected object. */ /* Both selecting, and moving the selected object. */ /*********************************************************************/ /*********************************************************************/ void update_world(WorldDataType *wd) void update_world(WorldDataType *wd) { { #define JS_EPSILON 0.125 /* the dead-zone befo #define JS_EPSILON 0.125 /* the dead-zone befo #define MOVE_FACTOR 2.5 /* a movement scale f #define MOVE_FACTOR 2.5 /* a movement scale f static vrTime last_time = -1.0; /* initially set to a static vrTime last_time = -1.0; /* initially set to a vrTime sim_time = vrCurrentSimTime(); /* the current time o vrTime sim_time = vrCurrentSimTime(); /* the current time o static vrPoint last_wand_locpnt; /* location of the wa static vrPoint last_wand_locpnt; /* location of the wa vrPoint wand_locpnt; /* current location o vrPoint wand_locpnt; /* current location o #define last_wand_loc last_wand_locpnt.v #define last_wand_loc last_wand_locpnt.v #define wand_location wand_locpnt.v #define wand_location wand_locpnt.v double delta_time; /* time since last up double delta_time; /* time since last up double joy_x, joy_y; /* Joystick values */ double joy_x, joy_y; /* Joystick values */ int selected_obj; /* the currently sele int selected_obj; /* the currently sele int touch_obj = -1; /* the currently touc int touch_obj = -1; /* the currently touc int objnum; /* for looping throuh int objnum; /* for looping throuh ObjectType *object; /* pointer to object ObjectType *object; /* pointer to object /*****************************************************/ /*****************************************************/ /** Determine delta time from last simulation frame **/ /** Determine delta time from last simulation frame **/ /*****************************************************/ /*****************************************************/ if (last_time == -1.0) if (last_time == -1.0) delta_time = 0.0; delta_time = 0.0; else delta_time = sim_time - last_time; else delta_time = sim_time - last_time; last_time = sim_time; /* now that delta_tim last_time = sim_time; /* now that delta_tim /* skip the update if the delta isn't big enough */ /* skip the update if the delta isn't big enough */ if (delta_time <= 0.0) /* can also choose a non-zero epsilon */ if (delta_time <= 0.0) /* can also choose a non-zero epsilon */ return; return; /**************************/ /**************************/ /* User interface section */ /* User interface section */ /* store input values so they are consistent throughout update routin /* store input values so they are consistent throughout update routin joy_x = vrGetValuatorValue(0); joy_x = vrGetValuatorValue(0); joy_y = vrGetValuatorValue(1); joy_y = vrGetValuatorValue(1); vrLockWriteSet(wd->lock); /* now use those values to move the object */ /* now use those values to move the object */ if (fabs(joy_x) > JS_EPSILON) if (fabs(joy_x) > JS_EPSILON) wd->object[2].x += joy_x * delta_time * MOVE_FACTOR; wd->object[2].x += joy_x * delta_time * MOVE_FACTOR; if (fabs(joy_y) > JS_EPSILON) if (fabs(joy_y) > JS_EPSILON) wd->object[2].z -= (joy_y-copysign(JS_EPSILON,joy_y)) * delta wd->object[2].z -= (joy_y-copysign(JS_EPSILON,joy_y)) * delta vrLockWriteRelease(wd->lock); /**********************************/ /**********************************/ /** Handle Manipulation via wand **/ /** Handle Manipulation via wand **/ /**********************************/ /**********************************/ /**********************************************************/ /**********************************************************/ /* check for contact between the wand and all the objects */ /* check for contact between the wand and all the objects */ /* Note, this is very course locking. We could also lock just */ /* around the lines that actually access the world database. */ vrLockReadSet(wd->lock); vrPointGetRWFrom6sensor(&wand_locpnt, WAND_SENSOR); vrPointGetRWFrom6sensor(&wand_locpnt, WAND_SENSOR); for (objnum = 0; objnum < wd->number_of_objects; objnum++) { for (objnum = 0; objnum < wd->number_of_objects; objnum++) { if ( (wand_location[VR_X] < wd->object[objnum].x + 1.0) if ( (wand_location[VR_X] < wd->object[objnum].x + 1.0) && (wand_location[VR_X] > wd->object[objnum].x - 1.0) && (wand_location[VR_X] > wd->object[objnum].x - 1.0) && (wand_location[VR_Y] < wd->object[objnum].y + 1.0) && (wand_location[VR_Y] < wd->object[objnum].y + 1.0) && (wand_location[VR_Y] > wd->object[objnum].y - 1.0) && (wand_location[VR_Y] > wd->object[objnum].y - 1.0) && (wand_location[VR_Z] < wd->object[objnum].z + 1.0) && (wand_location[VR_Z] < wd->object[objnum].z + 1.0) && (wand_location[VR_Z] > wd->object[objnum].z - 1.0) ) { && (wand_location[VR_Z] > wd->object[objnum].z - 1.0) ) { touch_obj = objnum; touch_obj = objnum; } } } } selected_obj = wd->selected_object; selected_obj = wd->selected_object; vrLockReadRelease(wd->lock); if (selected_obj != touch_obj) { if (selected_obj != touch_obj) { /* NOTE: a local variable (touch_obj) is used because it */ /* decreases the time the lock must be held. */ vrLockWriteSet(wd->lock); wd->selected_object = touch_obj; wd->selected_object = touch_obj; vrLockWriteRelease(wd->lock); selected_obj = touch_obj; selected_obj = touch_obj; } } /**** begin new code from example 9 ****/ /* when left wand button is pressed, the selected object is moved */ /* when left wand button is pressed, the selected object is moved */ if (vrGet2switchValue(1) && (selected_obj != -1)) { if (vrGet2switchValue(1) && (selected_obj != -1)) { vrLockWriteSet(wd->lock); object = &(wd->object[selected_obj]); object = &(wd->object[selected_obj]); object->x += (wand_location[VR_X] - last_wand_loc[VR_X]); object->x += (wand_location[VR_X] - last_wand_loc[VR_X]); object->y += (wand_location[VR_Y] - last_wand_loc[VR_Y]); object->y += (wand_location[VR_Y] - last_wand_loc[VR_Y]); object->z += (wand_location[VR_Z] - last_wand_loc[VR_Z]); object->z += (wand_location[VR_Z] - last_wand_loc[VR_Z]); vrLockWriteRelease(wd->lock); } } /******************************************************************/ /******************************************************************/ /* store the current wand location for next time through the loop */ /* store the current wand location for next time through the loop */ last_wand_loc[VR_X] = wand_location[VR_X]; last_wand_loc[VR_X] = wand_location[VR_X]; last_wand_loc[VR_Y] = wand_location[VR_Y]; last_wand_loc[VR_Y] = wand_location[VR_Y]; last_wand_loc[VR_Z] = wand_location[VR_Z]; last_wand_loc[VR_Z] = wand_location[VR_Z]; /**** end new code ****/ /****************************************************/ /****************************************************/ /* yield to allow other processes access to the CPU */ /* yield to allow other processes access to the CPU */ vrSleep(0); vrSleep(0); } } /* ----------------8<-----------------8<-----------------8<----------------*/ /* ----------------8<-----------------8<-----------------8<----------------*/ /* In a non-example applicatation, the following would be a separate file. */ /* In a non-example applicatation, the following would be a separate file. */ /**************************/ /**************************/ /**************************/ /**************************/ /** The Graphics section **/ /** The Graphics section **/ /**************************/ /**************************/ /**************************/ /**************************/ /* functions from shapes.c */ /* functions from shapes.c */ void draw_cube(); void draw_cube(); void draw_pyramid(); void draw_pyramid(); void draw_cube_outline(); void draw_cube_outline(); void draw_pyramid_outline(); void draw_pyramid_outline(); /*********************************************************************/ /*********************************************************************/ /* init_gfx(): initialize general graphics properties (eg. lighting) */ /* init_gfx(): initialize general graphics properties (eg. lighting) */ /*********************************************************************/ /*********************************************************************/ void init_gfx(void) void init_gfx(void) { { GLfloat location_0[4] = { 0.0, 10.0, 10.0, 1.0 /* 0 = directional, 1 GLfloat location_0[4] = { 0.0, 10.0, 10.0, 1.0 /* 0 = directional, 1 ambient_0[4] = { 0.2, 0.2, 0.2, 1.0 }, ambient_0[4] = { 0.2, 0.2, 0.2, 1.0 }, diffuse_0[4] = { 0.8, 0.8, 0.8, 1.0 }, diffuse_0[4] = { 0.8, 0.8, 0.8, 1.0 }, specular_0[4] = { 0.2, 0.2, 0.2, 1.0 }; specular_0[4] = { 0.2, 0.2, 0.2, 1.0 }; /****************************************/ /****************************************/ /* set the render initialization values */ /* set the render initialization values */ glClearColor(0.0, 0.0, 0.0, 0.0); glClearColor(0.0, 0.0, 0.0, 0.0); glClearDepth(1.0); glClearDepth(1.0); /********************************************************/ /********************************************************/ /* set the polygon shading/lighting/material parameters */ /* set the polygon shading/lighting/material parameters */ glShadeModel(GL_SMOOTH); glShadeModel(GL_SMOOTH); glEnable(GL_LIGHTING); glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0, GL_POSITION, location_0); glLightfv(GL_LIGHT0, GL_POSITION, location_0); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_0); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_0); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_0); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_0); glLightfv(GL_LIGHT0, GL_SPECULAR, specular_0); glLightfv(GL_LIGHT0, GL_SPECULAR, specular_0); glEnable(GL_LIGHT0); glEnable(GL_LIGHT0); /* These two lines cause the vertex colors to be used (otherwise all /* These two lines cause the vertex colors to be used (otherwise all glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glEnable(GL_COLOR_MATERIAL); glEnable(GL_NORMALIZE); /* this is required when calling glScalef() w glEnable(GL_NORMALIZE); /* this is required when calling glScalef() w /***************************/ /***************************/ /* set the line parameters */ /* set the line parameters */ glEnable(GL_LINE_SMOOTH); glEnable(GL_LINE_SMOOTH); glLineWidth(2.0); glLineWidth(2.0); } } /*******************************************************************/ /*******************************************************************/ /* draw_world(): Now will render how ever many objects are in the */ /* draw_world(): Now will render how ever many objects are in the */ /* world data structure. The color, type (and maybe rotation) */ /* world data structure. The color, type (and maybe rotation) */ /* are all now stored for each object, in addition to location. */ /* are all now stored for each object, in addition to location. */ /* The currently selected object is highlighted by adding a */ /* The currently selected object is highlighted by adding a */ /* wireframe outline to the representation. */ /* wireframe outline to the representation. */ /*******************************************************************/ /*******************************************************************/ void draw_world(WorldDataType *wd, vrRenderInfo *rendinfo) void draw_world(WorldDataType *wd, vrRenderInfo *rendinfo) { { static GLfloat location_0[4] = { 0.0, 10.0, 0.0, 1.0 /* 0 = directio static GLfloat location_0[4] = { 0.0, 10.0, 0.0, 1.0 /* 0 = directio static char msg[128]; /* memory for text st static char msg[128]; /* memory for text st int objnum; /* object counter */ int objnum; /* object counter */ /**************************************/ /**************************************/ /* clear the screen -- very important */ /* clear the screen -- very important */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /******************************************************************** /******************************************************************** /* update the light's location -- must be done independently for each /* update the light's location -- must be done independently for each glLightfv(GL_LIGHT0, GL_POSITION, location_0); glLightfv(GL_LIGHT0, GL_POSITION, location_0); /************************************/ /************************************/ /* draw a short pointer at the wand */ /* draw a short pointer at the wand */ glPushMatrix(); glPushMatrix(); glColor3ub(100, 255, 255); /* cyan */ glColor3ub(100, 255, 255); /* cyan */ vrRenderTransform6sensor(rendinfo, WAND_SENSOR); vrRenderTransform6sensor(rendinfo, WAND_SENSOR); glRotatef(-90.0, 1.0, 0.0, 0.0); glRotatef(-90.0, 1.0, 0.0, 0.0); glScalef(0.15, 0.15, 0.15); glScalef(0.15, 0.15, 0.15); glTranslatef(0.0, 1.5, 0.0); glTranslatef(0.0, 1.5, 0.0); draw_pyramid_outline(); draw_pyramid_outline(); glPopMatrix(); glPopMatrix(); /************************/ /************************/ /* draw all the objects */ /* draw all the objects */ /* Note again, this is very course locking. */ vrLockReadSet(wd->lock); for (objnum = 0; objnum < wd->number_of_objects; objnum++) { for (objnum = 0; objnum < wd->number_of_objects; objnum++) { glColor3ubv(wd->object[objnum].color); glColor3ubv(wd->object[objnum].color); glPushMatrix(); glPushMatrix(); glTranslatef(wd->object[objnum].x, wd->object[objnum] glTranslatef(wd->object[objnum].x, wd->object[objnum] switch (wd->object[objnum].shape) { switch (wd->object[objnum].shape) { case cube: case cube: if (objnum == wd->selected_object) if (objnum == wd->selected_object) draw_cube_outline(); draw_cube_outline(); else draw_cube(); else draw_cube(); break; break; case pyramid: case pyramid: if (objnum == wd->selected_object) if (objnum == wd->selected_object) draw_pyramid_outline(); draw_pyramid_outline(); else draw_pyramid(); else draw_pyramid(); break; break; case ud_pyramid: case ud_pyramid: glScalef(1.0, -1.0, 1.0); glScalef(1.0, -1.0, 1.0); if (objnum == wd->selected_object) if (objnum == wd->selected_object) draw_pyramid_outline(); draw_pyramid_outline(); else draw_pyramid(); else draw_pyramid(); break; break; } } glPopMatrix(); glPopMatrix(); } } /*************************************************/ /*************************************************/ /* draw text indicating which object is selected */ /* draw text indicating which object is selected */ if (wd->selected_object < 0) { if (wd->selected_object < 0) { sprintf(msg, "Object selected: none"); sprintf(msg, "Object selected: none"); } else { } else { sprintf(msg, "Object selected: %d", wd->selected_object); sprintf(msg, "Object selected: %d", wd->selected_object); } } vrLockReadRelease(wd->lock); glDisable(GL_LIGHTING); /* make the text bright regardless of glDisable(GL_LIGHTING); /* make the text bright regardless of glColor3ub(255, 255, 255); /* white */ glColor3ub(255, 255, 255); /* white */ glPushMatrix(); glPushMatrix(); glTranslatef(-4.0, 7.0, -5.0); /* on the front screen */ glTranslatef(-4.0, 7.0, -5.0); /* on the front screen */ glRasterPos3f(0.0, 0.0, 0.0); /* go to the 3D location */ glRasterPos3f(0.0, 0.0, 0.0); /* go to the 3D location */ vrRenderText(rendinfo, msg); vrRenderText(rendinfo, msg); glPopMatrix(); glPopMatrix(); glEnable(GL_LIGHTING); glEnable(GL_LIGHTING); } }