CSCI-B582 - Lecture 2.2
Outline - CAVE Programming w/ CAVELib & OpenGL
Credits: includes notes, examples, and diagrams
adapted from Dave Pape, NCSA Vis group, and VRCO
CAVELib & OpenGL
-
CAVElib functions
-
configures the display device (creates and maps windows & viewports)
-
forks and synchronizes processes and processors
-
draws stereoscopic views
-
monitors the trackers
-
monitors the controllers (i.e. wand)
-
supports coordinate system conversions
-
OpenGL features and modes assumed and automatically handled by CAVELib
-
RGB mode
-
z-buffering
-
double-buffering (handles buffer swaps too)
-
stereo (quad buffer)
-
establishing view matrix
-
establishing projection matrix
-
(other features (e.g. A buffer, stencil planes, multisampling) available
through CAVESetOption())
-
OpenGL is needed for all rendering
-
clear color
-
materials
-
lights
-
textures
-
geometry
-
normals
Multi-process structure of a CAVE application
-
CAVE Program Shell
-
Initialization and Callback Functions
-
CAVEConfigure() - reads configuration and initializes library data
-
CAVEInit() - forks other CAVE processes
-
CAVEInitApplication() - defines one-time graphics callback function
-
CAVEFrameFunction() - defines once-per-frame graphics callback
-
CAVEDisplay() - defines graphics callback which draws frame
-
CAVEExit() - signals all processes to exit
-
Overview Diagram
-
A detailed view of the app and display processes

Shared memory
-
CAVE applications use shared memory for communication between the various
processes of the application.
-
You should avoid doing interaction and simulation computations in the display
processes; these are best done in the application process with the results
stored in shared memory.
-
Common Shared Memory Functions
-
void * CAVEMalloc(size_t size)
Returns a pointer to a chunk of shared memory of size bytes.
This memory is allocated from the shared arena created by CAVEConfigure().
-
CAVEFree(void *p)
Frees shared memory which was allocated by CAVEMalloc().
-
CAVESetOption(CAVE_SHMEM_SIZE, int size)
Sets the size of the shared arena that CAVEMalloc() will use. The default
is 8 MB. This must be called before CAVEConfigure().
-
The memory arena used by CAVEMalloc is allocated during the call to CAVEConfigure.
Calling CAVEInit forks the rendering processes. So calls to CAVEMalloc
must come after CAVEConfigure and before CAVEInit.
-
Examples
Process Synchronization
-
Sometimes, the multiple display processes must be coordinated, such as
when they access shared data. The master display and displaybarriers can
be used for this.
-
At other times, access to shared memory must be synchronized between the
computation and display processes. CAVELOCKs provide two-level access control
- read and write.
-
Yet another diagram

-
Process Synchronization Functions
-
boolean CAVEMasterDisplay(void)
Returns TRUE in exactly one display process.
-
boolean CAVEMasterWall(void)
Returns TRUE if called by the master drawing process when it is drawing
the 'master' wall.
-
void CAVEDisplayBarrier(void)
Blocks the calling process until all the display processes have reached
the barrier. This should be called only in the display processes.
-
void CAVEDisplaySync(void)
Blocks the calling computation process until the end of the current
display frame.
-
CAVELOCK CAVENewLock(void)
Returns a new CAVE lock.
-
CAVEFreeLock(CAVELOCK lock)
Deletes a lock created by CAVENewLock().
-
CAVESetReadLock(CAVELOCK lock)
-
CAVEUnsetReadLock(CAVELOCK lock)
Sets/releases a lock for read access. Any number of processes may set
a lock for reading simultaneously. CAVESetReadLock() blocks until the lock
is set.
-
CAVESetWriteLock(CAVELOCK lock)
-
CAVEUnsetWriteLock(CAVELOCK lock)
Sets/releases a lock for write access. Only one process may set a lock
for writing at a time, and no processes may set the lock for reading while
it is write-locked. CAVESetWriteLock() blocks until the lock is set.
Interaction Methods
Tracking
-

-
Tracking is needed for two things: accurate viewer-centered perspective,
and interaction in 3D. The CAVE library and tracking daemon handle
all the details of reading the tracker hardware. Applications merely read
the final data (in CAVE coordinates) from shared memory, using CAVE library
functions.
-
Tracker functions
-
CAVEGetPosition (CAVEID id, float pos[3])
Returns the current position of the head, the wand, or an eye. id indicates
which position to return - it can be CAVE_HEAD, CAVE_WAND, CAVE_LEFT_EYE,
or CAVE_RIGHT_EYE.
-
CAVEGetOrientation (CAVEID id, float ori[3])
Returns the current orientation of the head or the wand, in Euler angles.
id indicates which position to return - CAVE_HEAD or CAVE_WAND. ori consists
of the rotation about X, about Y, and about Z; the angles are in degrees.
-
CAVEGetVector (CAVEID id, float vec[3])
Returns a unit-length vector for the head or wand, pointing in a given
direction, based on the current orientation. id indicates which vector
to return; it can be CAVE_HEAD_FRONT, CAVE_HEAD_BACK, CAVE_HEAD_LEFT, CAVE_HEAD_RIGHT,
CAVE_HEAD_UP, CAVE_HEAD_DOWN, CAVE_WAND_FRONT, ... . controller values
Controller
-

-
A "controller" provides additional input for interaction. Normally, this
controller is the EVL wand, which has 3 buttons and a pressure-sensitive
joystick. In general, a controller is a collection of on/off buttons and
floating-point valuators. The current state of the wand (buttons, joystick,
or other valuators) is also read by the CAVE tracking process, and is stored
in shared memory for application use.
-
Controller (Wand) functions
-
CAVEBUTTON1, CAVEBUTTON2, CAVEBUTTON3
Macros for the current state of the wand buttons. The value is 0 when
the button is released, non-zero when it is pressed.
-
int CAVEButtonChange(int button)
Returns a flag indicating the change in a button's state, compared
to the last time the function was called. 0 indicates the button has not
changed, 1 indicates that it has been pressed, and -1 indicates that is
has been released. button should be 1, 2, 3, or 4. The button states are
remembered by this function in each process independently.
-
CAVE_JOYSTICK_X, CAVE_JOYSTICK_Y
Macros for the current state of the wand joystick. The values are floats,
normally in the range -1.0 to 1.0. When the joystick is not being pushed,
the X and Y will be close to, but not exactly, 0.
-
Keyboard functions
-
boolean CAVEgetbutton(CAVE_DEVICE_ID device)
A CAVE equivalent to the IrisGL function getbutton(); returns the state
of a button device. device should be one of the CAVE device names listed
in cave.h; the names are the same as those used by IrisGL, except prefixed
with CAVE_ (e.g. CAVE_AKEY). In IrisGL this function just calls getbutton()
for the corresponding GL device. In OpenGL this function consults a table
in shared memory which is updated whenever the main display process receives
X events; it can thus be called from any CAVE process (note that the mouse
pointer must be in the master display's window for events to be received).
The tracking and wand data which is used by the library functions is updated
once per frame at the beginning of the frame, so that it is consistent
for all the drawing processes.
Examples: