CAVE User's Guide
CAVE Library version 2.6
May 11, 1997
- Electronic Visualization Laboratory
- University of Illinois at Chicago
- 851 S. Morgan St., Room 1120
- Chicago, IL 60607-7053
- (312) 996-3002
- (312) 413-7585 fax
- cavesupport@evl.uic.edu
Copyright 1996,1997 Electronic Visualization Laboratory, University
of Illinois at Chicago
written by Dave Pape, Carolina Cruz-Neira, Marek Czernuszenko
TABLE OF CONTENTS
- 3.1. Overall structure
- 3.2. Projectors and mirrors
- 3.3. Stereo glasses
- 3.4. Stereo emitters
- 3.5. Wand
- 3.6. Tracking systems
- 3.7. Audio system
- 3.8. Workstation
- 4.1. Immersadesk
- 4.2. Other Hardware
- 5.1. Introduction
- 5.2. Compiling a CAVE program
- 5.3. Display callbacks
- 5.4. Interaction
- 5.5. Navigation
- 5.6. Multiprocessing
- 5.7. Distributed CAVE
- 5.8. Networking
- 5.9. Form of a basic CAVE program
- 6.1. Overview
- 6.2. Data types
- 6.3. Basic CAVE functions
- 6.4. CAVE macros, variables, and miscellaneous
functions
- 6.5. Environment variables
- 6.6. Internal functions
- 7.1. Introduction
- 7.2. Simulated tracking
- 7.3. Simulated wand controls
- 7.4. Simulated display
- 10.1. CAVE sample program 1
- 10.2. CAVE sample program 2
1. Purpose of the CAVE User's Guide
This CAVE User's Guide contains all the information an application developer
needs to successfully create a CAVE experience.
- A description of the CAVE virtual reality system (Chapter 2)
- A list of the hardware components, particularly those with which a
programmer should be concerned (Chapters 3 & 4)
- A description of the CAVE software library (Chapters 5 & 6)
- A description of the most used development tool for CAVE applications,
the CAVE simulator (Chapter 7)
- A list of supporting software in the CAVE system directory (Chapter
8)
- A list of CAVE configuration options (Chapter 9)
- Sample programs (Chapter 10)
We assume that the reader has a basic knowledge of the C programming
language and is familiar with IrisGL or OpenGL.
I. Hardware
2. CAVE Description
The CAVE (CAVE Automatic Virtual Environment) is a projection-based
VR system that surrounds the viewer with 4 screens. The screens are arranged
in a cube made up of three rear-projection screens for walls and a down-projection
screen for the floor; that is, a projector overhead points to a mirror,
which reflects the images onto the floor. A viewer wears stereo shutter
glasses and a six-degrees-of-freedom head-tracking device. As the viewer
moves inside the CAVE, the correct stereoscopic perspective projections
are calculated for each wall. A second sensor and buttons in a wand held
by the viewer provide interaction with the virtual environment.
The current implementation of the CAVE uses three walls and the floor.
The projected images are controlled by an SGI Onyx with two Infinite Reality
graphics pipelines, each split into two channels. For testing, you can
run the CAVE using any number of walls simultaneously. The number of CAVE
walls used does not change your program. The CAVE library determines which
walls you want to use and does the necessary setup when your program starts.
A diagram of the CAVE environment is shown in Figure 1.

Figure 1: CAVE System
3. CAVE Equipment
3.1. Overall structure
CAVE hardware should be configured by system and video engineers so
it is usable. Under normal operation, CAVE users should only be concerned
with turning on and off the different components (although, due to ongoing
CAVE research, the hardware configuration could change occasionally, at
which time you should be notified by your system administrator.) The following
is a description of the CAVE equipment.
3.2. Projectors and mirrors
The projectors and the mirrors for the side walls are located behind
each wall. The projector for the floor is suspended from the ceiling of
the CAVE. The projectors are very sensitive to almost everything. It takes
at least one hour to align and calibrate each projector and mirror to match
at the corners of the CAVE. Please be careful not to move the projectors
or mirrors if you have to walk in that area.
Never turn off the projectors; this can cause them to go out of alignment.
Use the standby button on the remote control to activate them. Press and
hold the standby button on the remote control for a couple of seconds.
Do not touch any other control that might cause the projectors to go out
of alignment.
Once you are done using the CAVE, remember to put all the projectors
back in standby mode. The projector tubes have a limited life span that
can be extended by putting them on standby when not in use.
3.3. Stereo glasses
To see the virtual environment in stereoscopic 3D, users wear Stereographics'
CrystalEyes liquid crystal shutter glasses. The glasses are very fragile.
The glasses must be turned on by pressing a small button located on the
right side of the frame. To turn them off, press the same button. They
will not work if the user is facing away from the emitters.
3.4. Stereo emitters
The stereo emitters are little white boxes placed around the edges of
the CAVE. They are the devices that synchronize the stereo glasses to the
screen update rate of 120Hz or 96Hz. They are always on. You should not
have to do anything with them.
3.5. Wand
A wand (a 3D mouse) with buttons is the interactive input device. Currently,
EVL has two wands; both wands use the Ascension Flock of Birds tracking
system, but have different control devices. The primary wand has three
buttons and a pressure-sensitive joystick. It is connected to the CAVE
through a PC which is attached to one of the Onyx's serial ports. A server
program on the PC reads data from the buttons and joystick and passes them
to the Onyx. The older wand just has three buttons, and is attached to
the mouse port of the Onyx. When using the older wand, be sure that the
mouse pointer is on the main screen (the ":0.0" display) while
the CAVE is running, or your program will not be able to detect the state
of the wand buttons.
3.6. Tracking systems
The CAVE supports several different tracking systems. The primary system
is an Ascension Technologies Flock of Birds. Alternative systems include
the Ascension Spacepad and the Logitech sonic tracker. There are also "simulated"
tracking options available, using either the keyboard and mouse or a spaceball.
The use of one or another is transparent to the CAVE programmer, since
it is defined in the CAVE configuration file. Systems typically have two
sensors, one for tracking the user's head, and another for the wand.
3.7. Audio system
The audio system components are: an Indy workstation, speakers, a MIDI
interface, and synthesizer.
The Indy functions as a "sound server" for the CAVE. Commands
are sent to the workstation over the network, and it then either generates
sounds internally, or controls the synthesizer.
The speakers are located in the corners of the CAVE. They are always
turned on. DO NOT TOUCH any of the controls on the speakers. Everything
is controlled from the synthesizer.
The MIDI interface and synthesizer are located on a rack next to the
CAVE.
3.8. Workstation
The current implementation of the CAVE runs using a Silicon Graphics
Onyx with three Reality Engine 2s. Each Reality Engine is attached to a
CAVE wall.
4. ImmersaDesk and Other Hardware
4.1 Immersadesk
The ImmersaDesk is a drafting-table format virtual prototyping device.
The ImmersaDesk features a 4x5-foot rear-projected screen at a 45-degree
angle. The size and position of the screen give a wide-angle view and the
ability to look down as well as forward.
A diagram of the Immersadesk is shown in Figure 2.

Figure 2: Immersadesk Diagram
Except for the display device the same hardware is used as in the CAVE
- User wear CrystalEyes stereo glasses - turn them on by pressing a small
button located on the right side of the frame.
- Stereo emitters are placed behind the screen.
- Immersadesk can use various tracking systems, that the CAVE uses. There
are two primary systems:
- Logitech (ultrasonic)
- Ultrasonic emitter is placed on the top of the screen facing user.
- Head tracking: Special CrystalEyes glasses with tiny microphones.
Notice that if user bend to much over the screen, and he is not facing
the transmitter anymore he can get out of range. Green LED light on the
Logitech hardware will indicate this situation. There are two solution
to this problem:
- Flock of Birds
Same as in the CAVE.
4.2 Other Hardware
This page unintentionally left blank.
II. Software
5. CAVE Programming
5.1 Introduction
5.2 Compiling a CAVE program
A CAVE program should include the appropriate CAVE header file - either
cave.h for IrisGL programs or cave_ogl.h for OpenGL programs. IrisGL programs
will need to be linked with the CAVE library, the IrisGL library, and the
math library (-lcave -lgl -lm). OpenGL programs will need to be
linked with the OpenGL CAVE library, the OpenGL library, the math library,
and the X libraries (-lcave_ogl -lGL -lX11 -lXi -lm). The default
CAVE libraries are compiled in SGI's old 32-bit (O32) format. there are
also N32 and 64-bit versions of the OpenGL library; to use them, link with
-lcave_ogl_n32 or -lcave_ogl_64.
To use audio functions, include "vssClient.h" (after
"cave.h") and link with the sound
library (-lsnd).
All CAVE system files are normally found in /usr/local/CAVE; the headers
in /usr/local/CAVE/include and the libraries in /usr/local/CAVE/lib.
5.3. Display callbacks
Graphics in a CAVE program are handled using callback functions which
are called by the CAVE library's display loop for each view that must be
rendered. This approach is taken so that the library can take care of all
the necessary projections and synchronization.
The rendering for each wall of the CAVE is done by a separate process
(see Multiprocessing below). When
a stereo display is used, each process will call the application's display
function twice per frame; in monoscopic mode, it is called once per frame.
Because the application cannot know in advance how often the display function
will be called, a "frame function" callback is provided. This
callback will always be called exactly once per frame in each rendering
process, before the display callback. The third type of callback that is
available is the initialization callback. This function will be called
exactly once, at the beginning of the next frame after it is defined. This
can be used for any one-time display operations, such as defining materials
and textures.
An application's display callback function is defined by passing a function
pointer to CAVEDisplay. The frame function is defined with CAVEFrameFunction.
The initialization callback is defined using CAVEInitApplication.
Your program does not have to perform any window or projection commands.
The CAVE library does that for you, in order to produce the correct stereo
perspective. The CAVE by default is set to RGB mode, double buffered, with
z-buffering. Do not issue the swapbuffers command; it is handled internally
by the CAVE library. You are responsible for any other graphics commands,
such as lighting, object transformations, smoothing of lines, or clearing
the screen. The standard CAVE is a 10-foot cube. The origin of the coordinate
system (0, 0, 0) for the CAVE is normally located at the center of the
floor, that is, 5 feet away from any wall. This means that you have from
+5 to -5 feet horizontally and 0 to 10 feet vertically to define objects
inside the CAVE. The exact location of the CAVE origin is defined in the
configuration file by the "Origin" option. If you wish to change
its location, you must change all the configuration settings that
are given in CAVE coordinates (Origin, TransmitterPosition, and ProjectionData)
to use the same new coordinate system.
All the walls of the CAVE share the same reference coordinate system,
as shown in Figure 4. The coordinate system is a right-handed system. All
locations and orientations returned by the trackers to the CAVE library
will follow this convention.
By default, the near and far clipping planes of the CAVE are located
at 0.1 and 100.0 feet. Those values can be changed by modifying the global
variables CAVENear and CAVEFar.

Figure 4: CAVE Coordinates
5.4. Interaction
A user interacts with a CAVE application using the tracker and controller.
The tracker reports the position and orientation of its sensors; the controller
consists of a set of buttons which can be on or off, and valuators, such
as the joystick, which report floating point values (normally between -1
and 1).
The states of the tracker and controller are stored in structures in
shared memory. Several library functions are available to read this data,
and to compute derived values, such as tracker vectors. These structures
are updated between frames, once per display frame. Thus, the values will
remain constant during a given frame.
5.4.1. Trackers
In the past, the library supported exactly two tracked sensors - one
for the user's head, and one for the wand - and many of the functions reflect
this. The latest library supports up to 8 sensors (depending on the tracking
hardware). The sensor data is accessible through the global struct pointed
to by CAVEptr; the number of sensors being read is CAVEptr->num_sensors,
and the array CAVEptr->sensor contains pointers to the data for
each sensor. The first sensor (CAVEptr->sensor[0]) is always
the user's head; this is necessary for the proper display projections to
be generated. The remaining sensors are the wand or whatever other objects
are being tracked.
The functions for getting tracker-related values are:
- CAVEGetPosition(id,pos)
- CAVEGetOrientation(id,or)
- CAVEGetVector(id,vec)
- CAVEGetSensorPosition(sensor,coords,pos)
- CAVEGetSensorOrientation(sensor,coords,or)
- CAVEGetSensorVector(sensor,id,vec)
CAVEGetPosition, CAVEGetOrientation, and CAVEGetVector
return values for either the head or the wand (the first two sensors),
based on the id argument. CAVEGetSensorPosition, CAVEGetSensorOrientation,
and CAVEGetSensorVector return values for the sensor pointed to
by the sensor argument. These functions can return values either
in the coordinate system of the physical CAVE (that used by the trackers),
or in the application's world coordinate system (as defined by the navigation).
5.4.2. Controller
The status of the buttons and/or valuators on the wand (or other control
device) are stored in the global struct pointed to by CAVEController.
The typical CAVE wand has three or four buttons and a joystick (which consists
of two valuators - the X & Y position); there are macros for getting
these values. The macros are CAVEBUTTON1, CAVEBUTTON2, CAVEBUTTON3,
CAVEBUTTON4, CAVE_JOYSTICK_X, and CAVE_JOYSTICK_Y.
Note that, for historical reasons, the macros number the buttons starting
from 1, rather than 0, so CAVEBUTTON1 corresponds to CAVEController->button[0],
etc.
The values in CAVEController reflect the current state of the
buttons; the function CAVEButtonChange can be used to find out how
a button state has changed since the last time it was checked. The argument
for CAVEButtonChange uses the same numbering as the CAVEBUTTON
macros.
5.5. Navigation
The CAVE structure and tracking hardware generally limit a user's movements
to a 10 foot square area or smaller. This is not enough space for many
applications, so it is necessary to introduce a navigation coordinate transformation
which can move the CAVE's physical coordinate system around in the virtual
space. The CAVE library maintains a navigation transformation matrix which
is controlled by various functions, and provides conversions between the
tracker (physical) and world (navigated) coordinate systems.
The basic functions for navigation are CAVENavTranslate, CAVENavRot,
and CAVENavScale. These functions are equivalent to the corresponding
IrisGL functions. The transformations are all defined in the physical CAVE
coordinate system; i.e. a CAVENavTranslate(0.0,0.0,-1.0) will move
the CAVE through the virtual world one unit in the direction of the front
wall, and a CAVENavRot(30.0,'y') will turn the CAVE by 30 degrees
to the left. The other functions for controlling the matrix are CAVENavLoadIdentity,
CAVENavLoadMatrix, CAVENavMultMatrix and CAVENavGetMatrix.
When the CAVE library calls an application's display function, the default
coordinate system is the physical coordinates. To use the navigated coordinates,
the application should call CAVENavTransform.
It is sometimes necessary to convert values between the physical and
navigated coordinate systems. The function CAVENavConvertCAVEToWorld
will take a position in physical coordinates and transform it into navigated
coordinates; CAVENavConvertWorldToCAVE will perform the reverse
transformation. CAVENavConvertVectorCAVEToWorld and CAVENavConvertVectorWorldToCAVE
will perform the same transformations for direction vectors instead of
positions.
The library stores the navigation matrix in shared memory, so these
functions can be called from any process.
5.6. Multiprocessing
The CAVE library splits an application up into several processes to
handle the different tasks involved in running the CAVE. The basic flow
of a CAVE program is shown in Figure 5.

Figure 5: Program flow
The different child processes are all forked by CAVEInit. Only
the parent application process will return from CAVEInit; the others
all start internal library functions. There is one display process per
active wall, one process for tracking (if tracking is enabled), and one
process for networking (if networking is enabled). The display processes
call application-provided callback functions; the FrameFunction callback
is called once per frame, and the Display callback is called either once
or twice, depending on whether the CAVE is running in stereo.
To maintain acceptable frame rates, the display processes should only
perform rendering. All computations should be done in parallel in the main
application process. The application and display processes have to use
shared memory for any common data that must be exchanged between them.
The functions CAVEMalloc and CAVEFree can be used to allocate
and release shared memory, in the same manner as malloc and free.
The amount of shared memory that can be allocated depends on the size of
the library's arena, which can set using CAVESetOption; this must
be done before calling CAVEConfigure, as that is where the arena
is created. Alternatively, CAVEUserSharedMemory can be called to
create a shared memory arena, which can then be used with amalloc
(part of SGI's standard libraries) to allocate memory from that arena.
For a shared arena and any global shared pointers to be visible to all
the processes, they should be allocated before CAVEInit is called.
Shared memory allocated from the arena after calling CAVEInit is
visible to all processes, but the pointer will need to be passed to any
processes other than the allocator.
Following this parallelized approach, it may be necessary to guarantee
that the computation process does not modify shared data while it is being
used by the display processes. There are (at least) two methods of dealing
with this problem. One method is to use locks or semaphores to limit simultaneous
access to shared data. The CAVE library includes convenience routings (CAVENewLock,
CAVEFreeLock, CAVESetReadLock, CAVEUnsetReadLock,
CAVESetWriteLock, CAVEUnsetWriteLock) which provide two-level
access control. If the display processes only read the shared data, setting
a read lock will allow any number of them to access the data at the same
time, while a write lock will allow exactly one process to change the data
at a time.
The other method of controlling shared memory is to double-buffer the
data. In this case, the display processes have a pointer to one copy of
the data which will not change while they are rendering, and the computation
process makes changes to a separate copy of the data. When the computation
process finishes updating the shared data, it can swap buffers with the
display processes by calling CAVEDisplay with the pointer to the
updated data as an argument for the callback function. CAVEDisplay
blocks until the end of the current frame; this guarantees that the data
for the display processes will only change between frames.
As noted above, the library will fork a separate process for each of
the active CAVE walls. This means that the application's display function
may be called several times in parallel; the exact number of processes
varies depending on the CAVE configuration. In some cases, the display
function will perform an action that should only be done by one process
(such as diagnostic output or audio); for this, the function CAVEMasterDisplay
returns true for exactly one display process. Also, it is sometimes necessary
to synchronize the display processes, when shared memory is being modified;
the function CAVEDisplayBarrier will cause the processes to block
until all of them have called it. When using CAVEDisplayBarrier,
be sure that all the display processes will call it.
5.7. Distributed CAVE
Current SGI hardware will only allow up to three graphics pipes in a
single system. For a CAVE to have four walls, each with its own pipe, two
Onyxes must be used; this is referred to as a "distributed CAVE".
In a distributed CAVE, a separate copy of an application must be run on
each Onyx, and these systems need to be tightly synchronized and to share
data. The library includes functions to automatically share its own data
(tracking and navigation) and to synchronize the graphics displays. Fast,
low latency communications are needed, and so the distribution typically
uses Scramnet reflective memory, although HiPPI or standard TCP networks
may also be used. Basic functions are also provided for sharing application
data between the two machines.
To run a distributed CAVE application, the configuration options "Distribution"
and "AppDistribution" must be set appropriately (to Scramnet
or TCP). The "DistribID", and hardware related
options ("ScramnetDevices", etc.) must also be set; these
are normally defined in the system configuration file. One machine is considered
the master node - its DistribID is 0; the other machine, with DistribID
1, is the slave. The master node must be the system which does the
tracking. When distribution is enabled, the tracker data, controller state,
navigation matrix, and CAVE time are shared between the two machines; the
master node sends the latest values to the slave node at the beginning
of each frame.
If an application uses shared memory to communicate data between a computation
process and the display processes, this data will probably need to be shared
between the distributed CAVE nodes to guarantee that all the displays use
the same data. This can be done using standard networking libraries (RPC,
PVM, etc.) or with the CAVE library. To use the CAVE library functions
for distributing application data, the "AppDistribution"
configuration option must be set; it does not need to be the same as "Distribution".
The functions CAVEDistribWrite and CAVEDistribRead can then
be used to send and receive data between the two nodes; CAVEDistribMaster
can be used to have only the master node perform computations. CAVEDistribBarrier
synchronizes processes on the two nodes. When AppDistribution is
disabled, these functions will all return immediately without doing anything
(CAVEDistribMaster will always return true in this case). CAVEDistribOpenConnection
must be called before CAVEDistribWrite, CAVEDistribRead,
or CAVEDistribBarrier are called; all of these functions should
only be called from same process that called CAVEDistribOpenConnection
for the channel they use. CAVEDistribCloseConnection should be called
when the application exits, to close the communications channel.
5.8. Networking
The library includes an option for networking of CAVE applications,
whereby several users on different machines can share a virtual environment.
If networking is enabled (via the configuration), a separate process will
be started to handle it. This process automatically broadcasts the local
user's tracking and controller data to all other CAVEs in its group at
regular intervals. It also receives this data from the remote CAVEs and
stores it in shared memory in a list of the users who are currently in
the shared environment. Application-specific data can be passed to the
networking process in order for it to be broadcast to the other CAVEs.
To use the multicast networking with an application, a CAVE configuration
such as the following is needed:
Network mcast
NetworkAddress 224.2.242.117
NetworkPort 5302
NetworkAppPort 5303
NetworkTTL 4
NetworkUpdateInterval .05
All CAVEs which will be sharing the virtual world must use the same
network address and ports. The TTL controls how far packets will be broadcast
across routers and tunnels. The update interval sets how often the local
CAVE will broadcast its tracking data.
The global array CAVEUser contains pointers to structures with
the tracking and controller data for all the networked users. The current
number of networked users is stored in *CAVENumUsers. These values
are updated immediately whenever new data is received by the network process.
Different CAVEs will not necessarily be at the same location in the virtual
space, so their physical coordinate systems may not be the same. Hence,
all networked tracking data is in world coordinates (as controlled by the
CAVENav functions), so that all users will share a common frame
of reference. The functions CAVENetGetPosition, CAVENetGetOrientation,
and CAVENetGetVector return tracking data for networked users like
the corresponding local tracking functions.
Application callback functions can be defined to be called when a new
user is first added to the list, or when a user exits the application and
is removed from the list. These callbacks are defined using CAVEAddCallback.
The function CAVENetSend broadcasts application data. The data
can be received in two ways, either by calling CAVENetReceive or
by using a callback function. CAVENetReceive is non-blocking; if
no new application data has been received by the network process, it returns
immediately. If new data is available, it will be returned along with a
pointer to the network user struct for the remote CAVE which broadcast
the data. Alternatively, a callback can be defined with CAVEAddCallback;
this function will then be called automatically with any new application
data which is received. A program should only use one of CAVENetReceive
or an application data callback, not both.
Be aware that all network callback functions are called in the networking
process. They will need to use shared memory to communicate with the main
computation process or the display processes.
5.9. Form of a basic CAVE program
5.9.1. Program code
#include <cave.h>
void app_shared_init(), app_compute_init(),
app_init_gl(), app_draw(),
app_compute();
main(int argc,char **argv)
{
CAVEConfigure(&argc,argv,NULL);
app_shared_init(argc,argv);
CAVEInit();
CAVEInitApplication(app_init_gl,0);
CAVEDisplay(app_draw,0);
app_compute_init(argc,argv);
while (!getbutton(ESCKEY))
app_compute();
CAVEExit();
}
5.9.2. Program flow
CAVEConfigure(): This routine reads the CAVE configuration file,
and parses argc/argv for any user-specified configuration options.
app_shared_init(): This initializes anything that will be shared
by the computation and rendering processes (allocating shared memory, etc.).
Since all of the program's data that is not in shared memory will be duplicated
up to four times by the forks in CAVEInit, any large chunks of data that
do not need to be shared should be allocated after CAVEInit, to
save memory.
CAVEInit(): This routine initializes the CAVE. The primary operation
that it performs is to fork several processes. These processes are all
identical at this point. One process (the "computation process")
returns from CAVEInit and runs the rest of main(). The other processes
handle the tracking and rendering. There is one rendering process for each
wall. These processes call the application's GL init function once (whenever
one is given), and repeatedly call the application's drawing function.
CAVEInitApplication(), app_init_gl(): A pointer to the application's
graphics initialization function is passed to the rendering process. Since
the rendering is not done by the computation process (the one that returns
from CAVEInit), but by a separate rendering process, any GL initialization
needed for the rendering cannot be done directly by the computation process.
Instead, this function sets a pointer in shared memory to tell the rendering
process what function to call.
CAVEDisplay(), app_draw(): A pointer to the application's drawing
function is passed to the rendering process. As in the CAVEInitApplication
routine, this sets a pointer in shared memory to the function. The rendering
process then sees this pointer and calls the function itself.
app_compute_init(): This initializes any non-shared data that
will be used by the computation process.
app_compute(): This performs the application's computations.
Any results that are used by the drawing function should be stored in shared
memory.
CAVEExit(): This causes all CAVE processes to exit and restores
the machine to its normal state.
Note: If your program does nothing in the computation process (i.e.
app_compute() is empty), you should probably call sginap so that the computation
process doesn't waste a lot of CPU time that the other processes could
use. CAVEInitApplication does not have to be called if it is not needed.
When it is used, it should be called after CAVEInit and before CAVEDisplay.
6. CAVE Library
6.1. Overview
A library of C functions and macros has been developed to control the
operation of the CAVE. The CAVE library takes care of all the tasks that
have to be performed to correctly operate the CAVE. CAVE functions keep
all the devices synchronized, produce the correct perspective for each
wall, keep track of which walls are in use, and provide the applications
with the current state of all the CAVE elements. This section describes
in detail each of the routines and macros of the CAVE library.
NOTE: The names of all CAVE functions, macros, and global variables
start with the word CAVE (CAVEDisplay, for example).
6.2. Data types
The following data types are defined in cave.h and are used for
various CAVE function arguments or global variables.
CAVE_WALL_ID - an enumerated type for identifying the different
walls available in the CAVE, with values such as CAVE_FRONT_WALL,
CAVE_SCREEN0_WALL, CAVE_SIMULATOR_WALL, etc. There is a distinct
value for each wall which can be selected by the "Walls" configuration
option.
CAVEID - an enumerated type for most identifier constants other
than wall names.
CAVE_SENSOR_ST - a structure containing tracker sensor data.
The entries are:
- float x,y,z - the position of the sensor
- float azim,elev,roll - the orientation of the sensor (Euler
angles)
- CAVE_TIMESTAMP_ST timestamp - the time that the most recent
reading for this sensor was taken. The CAVE_TIMESTAMP_ST struct is similar
to a struct timeval, with entries sec and usec.
- boolean calibrated - a flag indicating whether the current sensor
data has been calibrated (see the CalibrationFile config option)
- CAVEID frame - the frame of reference for this data; either
CAVE_TRACKER_FRAME or CAVE_NAV_FRAME
The orientation values are in degrees; azim and roll range
from -180 to 180, and elev ranges from -90 to 90. The order of the
rotations is azim (Y), elev (X), roll (Z).
CAVE_CONTROLLER_ST - a structure containing controller status
information. The entries are:
- int num_buttons - number of buttons on the controller
- int button[] - state of each button
- int num_valuators - number of valuators on the controller
- float valuator[] - state of each valuator
CAVENETID - a unique ID for a networked CAVE user
CAVE_USER_ST - a structure containing data for a networked user.
The structure entries are:
- CAVENETID id - the user's ID
- float timestamp - the last time data was received from this
user (in local CAVE time)
- int num_sensors - the number of tracker sensors
- CAVE_SENSOR_ST sensor[] - the user's tracking data; sensor[0]
contains the head data; the remaining entries contain the data for the
wand and other tracked devices
- CAVE_CONTROLLER_ST controller - the user's controller data (buttons
& valuators)
- void *app_data - a pointer which can be used to store application
data associated with the user. The library does not touch this entry except
to zero it when a new user is initialized.
CAVELOCK - an IPC lock, as returned by CAVENewLock and
used by CAVESetReadLock, etc.
CAVECALLBACK - a pointer to a callback function (i.e. void
(*)())
CAVE_ST - a structure containing pointers to all the library
data for the CAVE. Some of the data are stored in shared memory; their
entries are therefore pointers, as the CAVE_ST structure itself
is not shared. The structure entries include:
- int num_sensors - the number of sensors being tracked
- CAVE_SENSOR_ST *sensor[] - the data from the tracker sensors
- CAVE_CONTROLLER_ST *controller - the controller status
- float *time - the current CAVE time; this is updated once per
display frame
- float *framesPerSecond - the current frame rate
- int *numUsers - the number of networked users
- CAVE_USER_ST **user - an array of pointers to the networked
users' data
6.3. Basic CAVE Functions
The following are the basic CAVE library functions which control the
operation of a CAVE program. CAVEInit, CAVEDisplay, and CAVEExit are used
by all CAVE applications; the rest are optional. These functions should
be called from your main process; they cannot be called from a rendering
process.
- void CAVEConfigure(int *argc,char **argv,char **appdefaults)
- Initializes the CAVE configuration. The CAVE library's internal shared
memory arena is created, the various global variables are initialized,
the configuration files are read, and then any configuration options given
in appdefaults or argc/argv are set (in that order). See
Section 9 for a description of the CAVE configuration
options.
appdefaults is an array of strings; each string should look just
like a line in a configuration file. The last entry in the array must be
NULL.
Options set with argc/argv consist of pairs of arguments; the first
argument is the keyword with a leading '-' (eg "-walls"), and
the second argument contains the rest of the option (eg "front left").
One additional option available with argc/argv is "-caveconfig",
which specifies another configuration file to read.
After calling CAVEConfigure, argc & argv will be modified to remove
all configuration options, leaving the rest of the command line for the
application. NULL may be passed for argc/argv or appdefaults.
CAVEConfigure is called by CAVEInit; if you call it directly, you should
do so before calling CAVEInit. Only the first call to CAVEConfigure
will do anything.
After everything has been read, the final CAVE configuration will be printed
to stderr. This printout can be disabled by setting the environment variable
CAVEDEBUGCONFIG to "OFF".
- void CAVEDisplay(CAVECALLBACK function,int num_args,...)
- This function passes the CAVE library a pointer to your drawing routine.
Your routine will be called by the rendering processes once per eye view
per frame (i.e. twice per frame for stereo, once per frame for monoscopic
mode). All rendering should be done from this routine; any GL calls made
directly by the main computation process will have no effect on what is
displayed in the CAVE. CAVEDisplay blocks until the next swapbuffers call
by the rendering processes.
The first argument is a pointer to the drawing routine. The second argument
is the number of arguments that the drawing routine receives (5 is the
maximum). If your routine does not take any arguments, pass zero (0). The
remainder are the arguments to be passed to your routine. These are stored
as void *'s, and so MUST be pointers (also, they should use shared memory
if they point to values that the computation process may change).
CAVEDisplay can only be called after CAVEInit.
- void CAVEExit(void)
- Ends a CAVE program. This function will signal all the CAVE processes
to halt, and then calls exit.
- void CAVEFrameFunction(CAVECALLBACK function,int num_args,...)
- This function passes the CAVE library a pointer to a routine which
should be called once per frame. The routine will be called exactly once
per frame whether the CAVE is in mono or stereo mode; it is called at the
beginning of a frame, before both the init and display routines. CAVEFrameFunction
blocks until the next swapbuffers call by the rendering processes.
The first argument is a pointer to the frame routine. The second argument
is the number of arguments that the routine receives (5 is the maximum).
If your routine does not take any arguments, pass zero (0). The remainder
are the arguments to be passed to your routine. These are stored as void
*'s, and so must be pointers.
CAVEFrameFunction can only be called after CAVEInit.
- void CAVEInit(void)
- Initializes the CAVE environment. This function starts the rendering
processes, and initializes the trackers and graphics. After CAVEInit is
called, the rendering processes are separate from the main computation
process; only the computation process will return to your program from
CAVEInit.
- void CAVEInitApplication(CAVECALLBACK function,int num_args,...)
- This function passes the CAVE library a pointer to your graphics initialization
routine. Your routine should do any GL initialization that is required
for your display functions. The rendering processes will call this routine
exactly once, at the beginning of the next frame. CAVEInitApplication blocks
until the next swapbuffers call by the rendering processes.
The first argument is a pointer to the graphics initialization routine.
The second argument is the number of arguments that the graphics initialization
routine receives (5 is the maximum). If your routine does not take any
arguments, pass zero (0). The remainder are the arguments to be passed
to your routine. These are stored as void *'s, and so must be pointers.
CAVEInitApplication should be called after CAVEInit, and before CAVEDisplay.
- void CAVEStopApplication(CAVECALLBACK function,int numargs,...)
- This function is used to suspend an application's display processes
without actually exiting. It clears the display, initialization, and frame
functions (set by CAVEDisplay, CAVEInitApplication, & CAVEFrameFunction),
and then has the display processes call function. This routine will
not return until after function has been called. Note: you do not
have to call CAVEStopApplication before exiting a CAVE program, unless
you want the graphics processes to call a "clean-up" function.
6.4. CAVE macros, variables, and miscellaneous
functions
CAVE macros simplify access to the wand information. The global variables
provide various information about the state of the CAVE.
6.4.1 Sensor & Controller macros
- CAVESENSOR(i)
- Macro for a pointer to the i'th tracking sensor; i.e. CAVEptr->sensor[i].
Sensor 0 is the head, sensors 1 and up are the wand or any other tracked
devices. This pointer can be passed to CAVEGetSensorPosition, CAVEGetSensorOrientation,
CAVEGetSensorVector, or CAVESensorTransform.
- CAVENETSENSOR(user,i)
- Macro for a pointer to the networked user user's i'th
tracking sensor; i.e. user->sensor[i]. Sensor 0 is the head,
sensors 1 and up are the wand or any other tracked devices.
- CAVEBUTTONn = [ 0 | 1 ]
- There are three buttons attached to the wand. They can be accessed
through the above macros, where n = 1, 2, 3, or 4. The macros have the
value 1 when the button is pressed, and 0 when not pressed.
CAVEBUTTON1 corresponds to the left wand button
CAVEBUTTON2 corresponds to the middle wand button
CAVEBUTTON3 corresponds to the right wand button
CAVEBUTTON4 corresponds to the fourth button on the Logitech flying mouse
- CAVE_JOYSTICK_X
- CAVE_JOYSTICK_Y
- The PC-based wand has a pressure-sensitive joystick in addition to
buttons. These two macros will give the X & Y coordinate values of
the joystick, normalized to be in the range [-1.0,1.0]. (Note: when the
joystick is not being pressed, these values will be close to, but not exactly,
0).
6.4.2 Global Variables
The following are global variables used by the CAVE library. CAVENear
and CAVEFar can be changed by an application. The other variables are meant
for information only; your program should not change them.
- int CAVENear,CAVEFar
- The near and far clipping plane distances for the CAVE's perspective
projection. These are not shared; each rendering process has independent
copies.
- int CAVEEye
- The eye view which is currently being drawn when your display function
is called; the possible values are CAVE_LEFT_EYE and CAVE_RIGHT_EYE. This
variable is not shared, since the rendering processes are not synchronized
except when they call swapbuffers.
- int CAVEWall
- The wall which is currently being drawn when your display function
is called. Possible values are CAVE_FRONT_WALL, CAVE_LEFT_WALL, CAVE_RIGHT_WALL,
CAVE_FLOOR_WALL, CAVE_BACK_WALL, CAVE_CEILING_WALL, CAVE_SCREEN[0-7]_WALL,
CAVE_SIMULATOR_WALL, CAVE_SIMULATOR1_WALL, and CAVE_SIMULATOR2_WALL. This
variable is only considered to be valid within the CAVEDisplay callback;
in non-rendering processes, and in the CAVEFrameFunction or CAVEInitApplication
callbacks its value is undefined.
- float *CAVEFramesPerSecond
- The current frame rate. This is pointer to a float because it is stored
in shared memory, and so is the same for all processes.
- float *CAVETime
- The current "CAVE time". This records the number of seconds
since CAVEInit. The variable is updated in the display loop, once per frame,
and is stored in shared memory.
- char *CAVEVersion
- A string identifying the version of the CAVE library. It contains the
version number and release date.
- CAVE_CONTROLLER_ST *CAVEController
- A structure containing the status of the wand controls. The 'button'
entry is an array of ints that give the state of the buttons (0 or 1);
the 'valuator' entry is an array of floats that give the state of any valuators.
The PC-based wand has two valuators - the joystick X and Y. The CAVEBUTTON
and CAVE_JOYSTICK macros access this structure.
- int *CAVENumUsers
- The number of networked users. This is the number of active nodes which
the network has received data from, plus the local node.
- CAVE_USER_ST **CAVEUser
- An array of networked user data. The first *CAVENumUsers entries
of CAVEUser are pointers to structures containing the tracking data
from the different nodes in the CAVE networking group. CAVEUser[0]
contains the local node's data. The other entries are not guaranteed to
always maintain the same position in the array; they may be moved as nodes
join and leave the networking group. However, the pointer to a given CAVE's
data will not change (unless the CAVE exits and then later rejoins the
group).
6.4.3 Miscellaneous Functions
- void CAVEAddCallback(CAVEID cbtype, CAVECALLBACK function, void
*app_data)
- Defines an application function which will be called by the library
when appropriate. cbtype is the type of callback; its value should
be one of: CAVE_DISPLAY_CALLBACK, CAVE_INITGRAPHICS_CALLBACK, CAVE_PERFRAME_CALLBACK,
CAVE_NETADDUSER_CALLBACK, CAVE_NETDELETEUSER_CALLBACK, or CAVE_NETAPPDATA_CALLBACK.
function is the application function to call; app_data is
an argument to pass to the callback function. Defining a CAVE_DISPLAY_CALLBACK
function is equivalent to calling CAVEDisplay; CAVE_INITGRAPHICS_CALLBACK
is equivalent to CAVEInitApplication; CAVE_PERFRAME_CALLBACK is
equivalent to CAVEFrameFunction.
The CAVE_NETADDUSER_CALLBACK will be called by the networking process whenever
a new user is added to the CAVEUser array.
The CAVE_NETDELETEUSER_CALLBACK will be called by the networking process
whenever a user is deleted from CAVEUser (a user is deleted when
no new data has been received from the user for a significant amount of
time).
The prototype for a networking add or delete callback is: void function(CAVE_USER_ST
*user,void *app_data). user is a pointer to the user structure
which is being added or removed; app_data is the application data
pointer which was passed to CAVEAddCallback.
The CAVE_NETAPPDATA_CALLBACK will be called by the networking process whenever
any application data (i.e. data sent via CAVENetSend) is received
from another node. If this callback is used, the data will not be read
by CAVENetReceive. The prototype for the net application data callback
is: void function(CAVE_USER_ST *user,void *buffer,size_t size,void *app_data).
user is a pointer to the user structure corresponding to the node
which sent the data; buffer is a buffer containing the data; size
is the size of the data in bytes; app_data is the application data
pointer which was passed to CAVEAddCallback.
Note: The networking callbacks are called in the networking process;
they should avoid using significant amounts of CPU time, or this process
will be slowed and the network data may be backed up.
- volatile void * CAVEAllocDisplayData(size_t size)
- Allocates shared memory to use for passing data to the display processes,
and returns a pointer to one block for the computation process to use.
size is the size of the block in bytes. Four blocks of memory are
actually allocated - the one that is returned, one for the display processes
to use, and two others that are used in staging the data when it is sent
by CAVEPassDisplayData(). The blocks are all allocated using CAVEMalloc(),
so its shared arena must be large enough to hold the four blocks, plus
any other shared data the application will allocate (the size can be set
by CAVESetOption()).
When this function is used instead of CAVEAllocDisplayDataByID(),
the application must make sure that all the calls occur in one process,
in the same order on all machines.
- volatile void * CAVEAllocDisplayDataByID(int id,size_t size)
- Equivalent to CAVEAllocDisplayData(), except that the application
provides an ID number (id) for the block of data being allocated,
in order to guarantee that corresponding blocks on separate nodes of a
distributed CAVE are matched together correctly. id must be a positive
integer.
- 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.
- float CAVEConvertFromCAVEUnits(float val,CAVEID units)
- Takes the distance val in CAVE units (the units specified in
the configuration file by CAVEUnits), and returns its equivalent
in the given units. units should be one of CAVE_FEET, CAVE_INCHES,
CAVE_METERS, or CAVE_CENTIMETERS.
- float CAVEConvertToCAVEUnits(float val,CAVEID units)
- Takes the distance val in the given units, and returns the equivalent
value in CAVE units (the units specified in the configuration file by CAVEUnits).
units should be one of CAVE_FEET, CAVE_INCHES, CAVE_METERS, or CAVE_CENTIMETERS.
- void CAVEDisplayBarrier(void)
- Provides a synchronization barrier for the display processes. When
this function is called from an application's display routine, it will
wait until all of the display processes reach the barrier before returning.
This function should not be called from any other processes; furthermore,
it must be called by all the display processes that the library started,
or the callers will block indefinitely.
- boolean CAVEDisplayDataChanged(volatile void *buf)
- Returns TRUE if a new copy of the display data buffer buf has
been passed to the display processes since the previous frame. buf
can be the pointer returned by CAVEAllocDisplayData() or one subsequently
returned by CAVEGetDisplayData().
- boolean CAVEDisplayDataChangedByID(int id)
- Equivalent to CAVEDisplayDataChanged(), except that the the
buffer is identified by it's ID number id, which is the ID passed
to CAVEAllocDisplayDataByID() (or returned by CAVEGetDisplayDataID()).
- boolean CAVEDisplayDataIDExists(int id)
- Returns TRUE if a display data buffer has been allocated for ID number
id, FALSE if not.
- void CAVEDisplaySync(void)
- Blocks the calling process until the end of the current rendering frame;
the call blocks on a semaphore which will be released by the master display
process just after the display buffers are swapped. Any number of processes
may use this function simultaneously. This should not be called from a
display process, or it will deadlock.
- void CAVEDistribBarrier(int chanID)
- Provides a synchronization barrier for separate nodes in a distributed
CAVE. The calling process will wait until the barrier is reached on all
of the distributed nodes before returning. This function should only be
called by one process on each node. chandID is the ID of a distribution
communications channel which was opened with CAVEDistribOpenConnection().
If distribution is not active, this function will return immediately.
- void CAVEDistribCloseConnection(int chanID)
- Closes a distributed CAVE communications channel. chanID is
the channel ID which was passed to CAVEDistribOpenConnection().
This function should be called by the process which calls CAVEDistribOpenConnection()
before exiting.
- boolean CAVEDistribMaster(void)
- Returns TRUE when called on the master node of a distributed CAVE;
FALSE for all other nodes. Returns TRUE when called in a non-distributed
(single node) CAVE.
- int CAVEDistribNumNodes(void)
- Returns the total number of nodes in the distributed CAVE. Returns
1 if distribution is not active.
- void CAVEDistribOpenConnection(int chanID)
- Opens a communication channel between the master and slave nodes of
the distributed CAVE. chanID is an integer identifying the channel;
it must be in the range 0 to CAVE_DISTRIB_MAX_CHANNELID (defined in cave.h,
currently 31). Returns TRUE if successful, FALSE if the channel could not
be opened. Once the channel is opened, it can be used with CAVEDistribRead(),
CAVEDistribWrite(), CAVEDistribBarrier(), and CAVEDistribCloseConnection();
these functions should only be called in the same process which opened
the channel. Only one process on a CAVE node should open a given channel;
each channel must be opened by all nodes in a distributed CAVE.
- int CAVEDistribRead(int chanID,void *buffer,size_t size)
- Reads the next block of data sent over a distributed CAVE channel by
CAVEDistribWrite(). chanID is the channel ID which was passed
to CAVEDistribOpenConnection(); buffer is a buffer of at
least size bytes which the data will be copied into. The function's
returned value is the number of bytes received. This function blocks until
data is received, unless distribution is not being used, in which case
it returns immediately (with a value of 0).
On the master node, a single call to CAVEDistribRead() will receive
data from only one of the slave nodes, in no particular order; it should
be called once for each of the slaves (assuming they all call CAVEDistribWrite());
the number of slave nodes is CAVEDistribNumNodes()-1.
- void CAVEDistribWrite(int chanID,void *buffer,size_t size)
- Sends a block of data over a given distributed CAVE channel. chanID
is the channel ID which was passed to CAVEDistribOpenConnection();
buf is a pointer to the data to send; size is the number
of bytes to send. When called by the master node, this sends a copy of
the data to each of the slave nodes; when called by a slave node, this
sends the data only to the master. If distribution is not active, this
function will return immediately without doing anything.
- void CAVEFree(void *mem)
- Frees a chunk of shared memory which was allocated by CAVEMalloc().
- void CAVEFreeLock(CAVELOCK lock)
- Frees up a CAVE lock, releasing the shared memory that it uses. The
lock should be one returned by CAVENewLock().
- void CAVEGetActiveChannels(CAVEID wall[CAVE_NUM_WALL_IDS])
- Returns a set of flags indicating which views (channels) are being
rendered by the application. The data returned is similar to that returned
by CAVEGetPipeChannels(), except that it covers all of the running
display processes.
- 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).
- volatile void * CAVEGetDisplayData(volatile void *buf,size_t *size)
- Returns a pointer to the shared buffer with the latest display data
which has been passed to the display processes (by CAVEPassDisplayData()).
buf can be the pointer returned by CAVEAllocDisplayData()
or one subsequently returned by CAVEGetDisplayData(). If size
is non-NULL, it will return the number of bytes which were sent by CAVEPassDisplayData().
- volatile void * CAVEGetDisplayDataByID(int id,size_t *size)
- Equivalent to CAVEGetDisplayData(), except that the the buffer
is identified by it's ID number id, which is the ID passed to CAVEAllocDisplayDataByID()
(or returned by CAVEGetDisplayDataID()).
- int CAVEGetDisplayDataID(void *buf)
- Returns the ID number associated with the display data buffer buf.
- void CAVEGetEyePosition(CAVEID eye,float *x,float *y,float *z)
- Returns the position of an eye. The first argument indicates which
eye's position you are requesting; it should have the value CAVE_LEFT_EYE
or CAVE_RIGHT_EYE. The remaining three arguments return the position, in
CAVE coordinates.
- int CAVEGetFrameNumber(void)
- Returns the number of the frame currently being rendered. Frames are
numbered starting from 0, from the moment the display loop is started by
CAVEInit().
- void CAVEGetOrientation(CAVEID oname,float *angle)
- Returns the orientation of a sensor or eye. The oname argument
indicates which object's orientation you are requesting; it should be one
of CAVE_HEAD, CAVE_WAND, CAVE_LEFT_EYE, CAVE_RIGHT_EYE, CAVE_HEAD_NAV,
CAVE_WAND_NAV, CAVE_LEFT_EYE_NAV, or CAVE_RIGHT_EYE_NAV (note that the
eyes will have the same orientation as the head). The _NAV id's request
the values in navigated (world) coordinates; the other id's request tracker
coordinates. The orientation is returned in angle, which should
be an array of three floats; angle[0] is the elevation (X rotation),
angle[1] is the azimuth (Y rotation), and angle[2] is the
roll (Z rotation).
- void CAVEGetPipeChannels(CAVEID wall[CAVE_NUM_WALL_IDS])
- Returns a set of flags indicating which views (channels) are being
rendered by the calling display process (pipe). For each wall ID id,
wall[id] will be either CAVE_NULL, CAVE_LEFT_EYE, CAVE_RIGHT_EYE,
or CAVE_BOTH_EYES. CAVE_NULL indicates that neither eye-view for that wall
is being rendered by this pipe; CAVE_LEFT_EYE indicates that the left eye-view
is being rendered; CAVE_RIGHT_EYE indicates that the right eye-view is
being rendered; CAVE_BOTH_EYES indicates that both views are being rendered.
- void CAVEGetPosition(CAVEID posname,float *pos)
- Returns the position of a sensor or eye. The posname argument
indicates what position you are requesting; it should be one of CAVE_HEAD,
CAVE_WAND, CAVE_LEFT_EYE, CAVE_RIGHT_EYE, CAVE_HEAD_NAV, CAVE_WAND_NAV,
CAVE_LEFT_EYE_NAV, or CAVE_RIGHT_EYE_NAV. The _NAV id's request the values
in navigated (world) coordinates; the other id's request tracker coordinates.
The position is returned in pos, which should be an array of three
floats.
- void CAVEGetSensorOrientation(CAVE_SENSOR_ST *sensor,CAVEID frame,float
*angle)
- Returns the orientation of the tracked sensor whose data is pointed
to by sensor. sensor can be a locally tracked sensor, or
one from a networked user; the macros CAVESENSOR() and CAVENETSENSOR()
return appropriate pointers. frame indicates the frame of reference
for the returned data; it should be either CAVE_TRACKER_FRAME for physical,
tracker coordinates, or CAVE_NAV_FRAME for world, navigated coordinates.
The orientation is returned in angle, which should be an array of
three floats; angle[0] is the elevation (X rotation), angle[1]
is the azimuth (Y rotation), and angle[2] is the roll (Z rotation).
- void CAVEGetSensorPosition(CAVE_SENSOR_ST *sensor,CAVEID frame,float
*pos)
- Returns the position of the tracked sensor whose data is pointed to
by sensor. sensor can be a locally tracked sensor, or one
from a networked user; the macros CAVESENSOR() and CAVENETSENSOR()
return appropriate pointers. frame indicates the frame of reference
for the returned data; it should be either CAVE_TRACKER_FRAME for tracker
coordinates, or CAVE_NAV_FRAME for navigated coordinates. The position
is returned in pos, an array of three floats.
- void CAVEGetSensorVector(CAVE_SENSOR_ST *sensor,CAVEID vecname,float
*vec)
- Returns a unit vector of the tracked sensor whose data is pointed to
by sensor. sensor can be a locally tracked sensor, or one
from a networked user; the macros CAVESENSOR() and CAVENETSENSOR()
return appropriate pointers. vecname indicates which vector to return,
and its frame of reference. The allowed values for vecname are:
CAVE_FRONT, CAVE_BACK, CAVE_LEFT, CAVE_RIGHT, CAVE_UP, and CAVE_DOWN, or
any of these with the suffix _NAV. The _NAV forms return vectors in navigated
coordinates; the base forms return vectors in tracker coordinates. The
unit vector is returned in vec, an array of three floats.
- float CAVEGetTime(void)
- Returns the current "CAVE time", i.e. the number of seconds
since the CAVE was initialized. The difference between this and *CAVETime
is that CAVEGetTime computes the time when it is called, whereas
*CAVETime is only updated once per frame.
- long CAVEgetvaluator(CAVE_DEVICE_ID device)
- A CAVE equivalent to the IrisGL function getvaluator(); returns
the state of a valuator 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_MOUSEX). In IrisGL this function
just calls getvaluator() 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.
- void CAVEGetVector(CAVEID vectorid,float vector[3])
- Computes a given tracker unit vector. The vector to return is specified
by vectorid, which can be one of: CAVE_HEAD_FRONT, CAVE_HEAD_BACK,
CAVE_HEAD_LEFT, CAVE_HEAD_RIGHT, CAVE_HEAD_UP, CAVE_HEAD_DOWN, CAVE_WAND_FRONT,
CAVE_WAND_BACK, CAVE_WAND_LEFT, CAVE_WAND_RIGHT, CAVE_WAND_UP, CAVE_WAND_DOWN,
or any of these constants suffixed with _NAV (e.g. CAVE_HEAD_FRONT_NAV).
The _NAV constants request vectors in navigated coordinates; the other
constants request tracker coordinates. The unit vector is returned in vector.
- void CAVEGetViewport(int *origX,int *origY,int *width,int *height)
- Returns the origin and size of the viewport for the view currently
being rendered by the calling process. origX and origY return
the position of the lower left corner of the viewport, measured in pixels,
from the origin of the window within which the view is being drawn. width
and height return the size of the viewport in pixels. This function
should only be called from a CAVEDisplay callback.
- void CAVEGetWindowGeometry(int *origX,int *origY,int *width,int
*height)
- Returns the origin and size of the calling process's window (this function
should only be called in a display process). origX and origY
return the position of the lower left corner of the window, measured from
the lower left corner of the screen, in pixels. width and height
return the size of the window in pixels.
- GLXContext CAVEGLXContext(void)
- Returns a pointer to the calling process's GLX rendering context. This
should only be called from a display process. This function is only available
in the OpenGL CAVE library.
- void CAVEHalt(void)
- Tells all the child CAVE processes to exit. This performs the exact
same actions as CAVEExit(), except that it returns to the caller,
rather than calling exit().
- void CAVEHeadTransform(void)
- Sets up a transformation using the head tracking data, which can be
used to position an object at the same location and with the same orientation
as the user's head.
The transformation is relative to CAVE tracker coordinates; this function
should be called with no transformations active other than that initialized
by the CAVE library.
- int CAVEInStereo(void)
- Returns 1 if the CAVE is displaying stereoscopic images, 0 if it is
monoscopic. Note that CAVEInStereo() returning true does not necessarily
indicate that a rendering process will call the application's display function
twice per frame, as each eye's view could be being handled by a separate
process.
- void *CAVEMalloc(size_t size)
- Allocates a chunk of size bytes of shared memory. If no more
shared memory is available, NULL is returned. The memory may be freed by
CAVEFree(). The arena used by CAVEMalloc() is initialized
in CAVEConfigure(); CAVEMalloc() can be called at any time
after that.
- boolean CAVEMasterDisplay(void)
- Returns TRUE for the one process which is drawing the 'master' wall
(on a machine), FALSE for all others. This can be used when exactly one
display process should execute something. Note that the master display
process may be responsible for rendering other walls in addition to the
master wall; this function's return value depends only on which process
it is called in, not whether the master wall itself is currently being
drawn.
When running a distributed CAVE, each node has its own master display process;
CAVEMasterDisplay() will return TRUE for one process on each node.
- boolean CAVEMasterWall(void)
- Returns TRUE if the calling process is currently rendering the 'master'
wall.
When running a distributed CAVE, each node has its own master wall; CAVEMasterWall()
will return TRUE for one wall on each node.
- void CAVENavConvertCAVEToWorld(float inposition[3],float outposition[3])
- Converts a position (inposition) in physical CAVE coordinates
(such as a tracker position) to navigated world coordinates. The converted
position is returned in outposition.
- void CAVENavConvertVectorCAVEToWorld(float invector[3],float outvector[3])
- Converts a vector (invector) in the physical CAVE coordinate
system to the navigated world coordinate system. The converted vector is
returned in outvector.
- void CAVENavConvertVectorWorldToCAVE(float invector[3],float outvector[3])
- Converts a vector (invector) in the navigated world coordinate
system to the physical CAVE coordinate system. The converted vector is
returned in outvector.
- void CAVENavConvertWorldToCAVE(float inposition[3],float outposition[3])
- Converts a position (inposition) in navigated world coordinates
to physical CAVE coordinates (the coordinate system used by the trackers).
The converted position is returned in outposition.
- void CAVENavGetMatrix(Matrix m)
- Copies the current navigation transformation matrix into m.
- void CAVENavInverseTransform()
- Applies the inverse of the current navigation transformation. This
allows a program to switch from navigated coordinates to physical (tracker)
coordinates.
- void CAVENavLoadIdentity(void)
- Resets the navigation transformation matrix to identity.
- void CAVENavLoadMatrix(Matrix m)
- Replaces the navigation transformation matrix with the given matrix
m.
- void CAVENavLock(void)
- Sets a lock for controlling access to the navigation transformation
matrix. While the lock is set, the display processes will be blocked when
they try to make a copy of it for the next frame. This can be used to make
a series of navigation calls atomic; e.g.:
CAVENavLock();
CAVENavLoadIdentity();
CAVENavTranslate(x,y,z);
CAVENavRot(angle,'y');
CAVENavUnlock();
Locking is not needed around single navigation function calls, as that
is handled internally. A lock should not be set for very long periods,
as it will block the display processes and reduce the frame rate.
- void CAVENavMultMatrix(Matrix m)
- Post-multiplies the current navigation transformation matrix by the
given matrix m.
- void CAVENavPreMultMatrix(Matrix m)
- Pre-multiplies the current navigation transformation matrix by the
given matrix m. This corresponds to adding a transformation in world
coordinates.
- void CAVENavRot(float angle, char axis)
- Performs a rotation of the CAVE, adding it to the navigation transformation.
angle is in degrees; axis should be 'x', 'y', or 'z'.
- void CAVENavScale(float xscale, float yscale, float zscale)
- Performs a scaling of the CAVE, adding it to the navigation transformation.
- void CAVENavTransform()
- Applies the current navigation transformation. This should be called
in the draw routine when you wish to use world (navigated) coordinates
rather than physical (tracker) coordinates.
- void CAVENavTranslate(float xtrans, float ytrans, float ztrans)
- Performs a translation of the CAVE, adding it to the navigation transformation.
- void CAVENavUnlock(void)
- Releases the navigation lock set by CAVENavLock().
- void CAVENavWorldRot(float angle, char axis)
- Performs a rotation of the CAVE, adding it to the navigation transformation.
angle is in degrees; axis should be 'x', 'y', or 'z'. The
axis of rotation is defined in world coordinates, as opposed to the local
CAVE coordinates used in CAVENavRot().
- void CAVENavWorldScale(float xscale, float yscale, float zscale)
- Performs a scaling of the CAVE, adding it to the navigation transformation.
The scaling is specified in world coordinates.
- void CAVENavWorldTranslate(float xtrans, float ytrans, float ztrans)
- Performs a translation of the CAVE, adding it to the navigation transformation.
The translation is specified in world coordinates.
- CAVE_USER_ST * CAVENetFindUser(CAVENETID id)
- Returns a pointer to the user struct for the networked user with the
given ID. If no such user is found, NULL is returned.
- void CAVENetGetOrientation(volatile CAVE_USER_ST *user,CAVEID oname,float
*or)
- Returns the orientation of a networked user's sensor or eye. user
is a pointer to the user structure (an entry in CAVEUser) to get the data
from. oname indicates which object's orientation you are requesting;
it should be one of CAVE_HEAD, CAVE_WAND, CAVE_LEFT_EYE, CAVE_RIGHT_EYE,
CAVE_HEAD_NAV, CAVE_WAND_NAV, CAVE_LEFT_EYE_NAV, or CAVE_RIGHT_EYE_NAV.
The first four choices return data in the local CAVE's tracker coordinate
system; the last four return data in world (navigated) coordinates. (Note
that the eyes will have the same orientation as the head). The orientation
is returned in angle, which should be an array of three floats;
angle[0] is the elevation (X rotation), angle[1] is the azimuth
(Y rotation), and angle[2] is the roll (Z rotation).
- void CAVENetGetPosition(volatile CAVE_USER_ST *user,CAVEID posname,float
*pos)
- Returns the position of a networked user's sensor or eye. user
is a pointer to the user structure (an entry in CAVEUser) to get the data
from. posname indicates what position you are requesting; it should
be one of CAVE_HEAD, CAVE_WAND, CAVE_LEFT_EYE, CAVE_RIGHT_EYE, CAVE_HEAD_NAV,
CAVE_WAND_NAV, CAVE_LEFT_EYE_NAV, or CAVE_RIGHT_EYE_NAV. The first four
choices return positions in the local CAVE's tracker coordinate system;
the last four return positions in world (navigated) coordinates. The position
is returned in pos, which should be an array of three floats.
- void CAVENetGetVector(volatile CAVE_USER_ST *user,CAVEID vecname,float
*vec)
- Computes a given tracker unit vector for a networked user. user
is a pointer to the user structure (an entry in CAVEUser) to get the data
from. The vector to return is specified by vecname, which can be
one of: CAVE_HEAD_FRONT, CAVE_HEAD_BACK, CAVE_HEAD_LEFT, CAVE_HEAD_RIGHT,
CAVE_HEAD_UP, CAVE_HEAD_DOWN, CAVE_WAND_FRONT, CAVE_WAND_BACK, CAVE_WAND_LEFT,
CAVE_WAND_RIGHT, CAVE_WAND_UP, or CAVE_WAND_DOWN, or any of these names
suffixed with _NAV (e.g. CAVE_WAND_FRONT_NAV). The _NAV choices return
data in world coordinates; the other choices return data in the local CAVE's
tracker coordinate system. The unit vector is returned in vec.
- void CAVENetHeadTransform(volatile CAVE_USER_ST *user)
- Sets up a transformation using a networked user's head tracking data,
which can be used to position an object at the same location and with the
same orientation as that user's head. user is a pointer to the user
structure to get the data from.
- int CAVENetReceive(void *buf,size_t size,CAVE_USER_ST **user)
- Receives any application data which has been broadcast by another node
in the CAVE networking group. The data returned will be the result of exactly
one CAVENetSend() call. Data sent by the local application will
not be received. buf is a pointer to the buffer to store the data
in; size is the size of the buffer in bytes. user will return
a pointer to the user structure corresponding to the node which broadcast
the data. The return value is the number of bytes of data which were read;
it is 0 if no new packets were available. If the incoming packet is larger
than size, the excess bytes are discarded.
- void CAVENetSend(void *data,size_t size)
- Broadcasts application data to all other nodes in the CAVE networking
group. data is a pointer to the data to send; size is the
size of the data in bytes.
- void CAVENetWandTransform(volatile CAVE_USER_ST *user)
- Sets up a transformation using a networked user's wand tracking data,
which can be used to position an object at the same location and with the
same orientation as that user's wand. user is a pointer to the user
structure to get the data from.
- int CAVENewID(void)
- Returns a new, unique integer, which may be used as an ID number for
display data or a distributed CAVE channel.
- CAVELOCK CAVENewLock(void)
- Creates a new CAVE lock structure which can be used for mutual exclusion
between CAVE processes which use shared memory. A CAVE lock has two modes
- read locking and write locking. Any number of processes can set a lock
for read locking simultaneously; only one process can write lock it at
any time. The lock returned by this function can be passed to CAVESetReadLock(),
CAVESetWriteLock(), CAVEUnsetReadLock(), CAVEUnsetWriteLock(), and CAVEFreeLock().
The lock is created in shared memory; roughly 1300 locks can be allocated
given the current size of the CAVE library's arena.
On the Onyx, these locks use hardware spin-locks, which are not guaranteed
to prevent starvation.
- int CAVENumPipes(void)
- Returns the number of drawing processes ("pipes") which are
active.
- void CAVEPassAllDisplayData(void)
- Calls CAVEPassDisplayData() for all display data that has been
allocated.
- void CAVEPassDisplayData(volatile void *buf,size_t size)
- Sends data from the buffer buf, which was returned by CAVEAllocDisplayData(),
to the display processes. size is the number of bytes to send, starting
from the beginning of the buffer; if size is 0, the entire buffer
is sent. The data is copied from buf into one of the staging buffers,
which will then be returned by CAVEGetDisplayData() on the next
frame. When AppDistribution is active, this function should only be called
on the master node.
- void CAVEPassDisplayDataByID(int id,size_t size)
- Equivalent to CAVEPassDisplayData(), except that the the buffer
is identified by it's ID number id, which is the ID passed to CAVEAllocDisplayDataByID()
(or returned by CAVEGetDisplayDataID()).
- int CAVEPipeNumber(void)
- Returns a unique ID number for the calling drawing process ("pipe").
The pipe number will range from 0 to CAVENumPipes()-1. If called
from a non-drawing process, the return value is -1.
- CAVEID CAVEProcessType(void)
- Returns an identifier indicating what type of process it was called
from. The possible return values are CAVE_APP_PROCESS (for the main process
or any other process that the application forks from it), CAVE_DISPLAY_PROCESS
(for the rendering processes started by CAVEInit()), CAVE_TRACKER_PROCESS
(for the tracking process), CAVE_NETWORK_PROCESS (for the networking process),
and CAVE_DISTRIB_PROCESS (for the distribution administration process).
CAVE_TRACKER_PROCESS and CAVE_DISTRIB_PROCESS should never be seen by application
code, as those processes are handled entirely by the CAVE library; CAVE_NETWORK_PROCESS
should only be seen from the network data callback function.
- void CAVEResetTracker(void)
- Signals the tracking process to reset the tracker hardware (via the
SIGUSR2 signal).
- void CAVEScramnetFree(void *mem)
- Frees a chunk of shared memory which was allocated by CAVEScramnetMalloc().
- void * CAVEScramnetMalloc(size_t size)
- Allocates a chunk of size bytes of Scramnet shared memory. If
no more memory is available, NULL is returned. The memory may be freed
by CAVEScramnetFree(). Scramnet memory is replicated between machines
on the Scramnet network, and may be used for shared data in a distributed
CAVE. When used in a distributed CAVE application, each node must make
the exact same sequence of calls to CAVEScramnetMalloc() in order
to receive the same pointers for each allocation. NB: In order to use this
function, you must set the Scramnet arena size with CAVESetOption(CAVE_SCRAMNET_ARENASIZE,...),
as the default size is 0. The arena used by CAVEScramnetMalloc()
is initialized in CAVEConfigure(); CAVEScramnetMalloc() can
be called at any time after that.
- void CAVESensorTransform(CAVE_SENSOR_ST *sensor)
- Sets up a transformation using the given sensor's tracking data, which
can be used to position an object at the same location and with the same
orientation as the sensor. sensor can be a locally tracked sensor,
or one from a networked user; the macros CAVESENSOR() and CAVENETSENSOR()
return appropriate pointers.
The transformation is relative to CAVE tracker coordinates; this function
should be called with no transformations active other than that initialized
by the CAVE library.
- void CAVESetOption(CAVEID option,int value)
- Sets options for various library functions. Options which affect the
amount of memory allocated for CAVE operations (CAVE_NET_NUMBUFFERS, CAVE_NET_BUFFERSIZE,
CAVE_SHMEM_SIZE) must be set before calling CAVEConfigure(). Options
which affect the graphics initialization (CAVE_GL_SAMPLES, CAVE_GL_STENCILSIZE,
CAVE_GL_ACCUMSIZE) must be set before calling CAVEInit(). The options
available are:
- CAVE_DIST_NETWORKSLAVE
- A flag indicating whether the slave nodes in a distributed CAVE should
do networking. If true, all nodes will fork network processes for sending
and receiving data, although only the master will broadcast the tracking
data. If false, only the master node will be able to send or receive network
data, and only the master will have information about the other networked
CAVEs in the CAVEUser array. The default value is false (0).
- CAVE_GL_ACCUMSIZE
- The number of accumulation buffer bitplanes (per color component) that
should be allocated when the graphics windows are opened. The default value
is 0.
- CAVE_GL_SAMPLES
- The number of samples per pixel to be allocated in multisampling mode.
When this is 0, multisampling is not enabled; when non-zero, the non-multisampled
Z buffer and stencil sizes are set to 0. The default value is 0. If the
hardware does not support the number of samples requested, the largest
possible number of samples less than the request will be allocated.
- CAVE_GL_STENCILSIZE
- The number of stencil buffer bitplanes that should be allocated when
the graphics windows are opened. The default value is 0.
- CAVE_NET_BUFFERSIZE
- The size (in bytes) of the buffers that the networking process will
use for sending and receiving application data. The default value is 4096
bytes.
- CAVE_NET_NUMBUFFERS
- The number of buffers to use for queueing application data received
by the networking process. The default value is 32. This is only meaningful
if CAVENetReceive() is used; if an application data callback is
used instead, the library will not use a buffer queue.
- CAVE_NET_UPDATELOCALDATA
- A flag indicating whether CAVEUser[0] (the network data for
the local user) should be updated when networking is disabled. If value
is 1, the data will be updated once per frame by the master display process;
if it is 0, the data will not be updated. The update will always occur
if networking is enabled. The default value is 0.
This is useful for applications which make use of CAVEUser[0] and
will need the data updated even when networking is not active. Other applications
should leave it off to avoid unnecessary overhead in the display process.
- CAVE_PROJ_INCLUDENAVIGATION
- A flag indicating whether the navigation matrix should be included
in the CAVE's projection transformation. When this is enabled, rendering
will be in navigated, world coordinates by default, so CAVENavTransform()
should not be called. The default value is 0.
- CAVE_PROJ_USEWINDOW
- A flag indicating whether CAVEGetProjection() should use the
current window size when computing the projection for the simulator view.
The default value is 1.
- CAVE_PROJ_USEMODELVIEW
- A flag indicating whether the projection matrix set up by the CAVE
library's display loop should use the ModelView matrix for part of the
transformation. The default value is 1, in which case the GL Projection
matrix is used solely for the viewing frustum transformation, while transformations
based on the display wall's orientation and position are loaded in the
ModelView matrix (this is the traditional method). When the flag is 0,
the entire transformation is loaded in the Projection matrix; this mode
will make reflection-mapped textures match between walls of the CAVE; however,
it breaks fog.
- CAVE_SCRAMNET_ARENASIZE
- Defines the size of the Scramnet shared memory arena used by CAVEScramnetMalloc().
The size is limited by the amount of physical memory on the Scramnet card
(typically 128K or 2M), and by the amount of memory used for other purposes,
such as distributed CAVE synchronization. The default size is 0.
- CAVE_SHMEM_SIZE
- Defines the size of the shared arena used by CAVEMalloc(); value
is the arena size in bytes. This must be done before CAVEConfigure()
is called, as the arena cannot be changed once it is initialized. The default
arena size is 8 megabytes.
- CAVE_SHMEM_ADDRESS
- Defines the base address of the shared memory arena used by CAVEMalloc().
This defaults to 0x70000000.
- CAVE_SIM_DRAWOUTLINE
- A flag indicating whether the CAVE outline should be drawn in the simulator
display. This is equivalent to the Insert-key keyboard control. The default
value is 1.
- CAVE_SIM_DRAWTIMING
- A flag indicating whether the timing information should be drawn in
the simulator display. This is equivalent to the keyboard control 't'.
The default value is 0.
- CAVE_SIM_DRAWUSER
- A flag indicating whether the user's head should be drawn in the simulator
display. This is equivalent to the keyboard control 'u'. The default value
is 1.
- CAVE_SIM_DRAWWAND
- A flag indicating whether the wand icon should be drawn in the simulator
display. This is equivalent to the keyboard control 'w'. The default value
is 1.
- CAVE_SIM_VIEWMODE
- Selects which viewing mode to use in the simulator display; possible
values are 0, 1, and 2. This is equivalent to the keyboard controls '0'/'1'/'2'.
The default value is 1.
- CAVE_TRACKER_SIGNALRESET
- A flag indicating whether signals should be used for the tracker reset
function. CAVEResetTracker() sends a SIGUSR2 signal to the process
handling tracking, to cause it to call the actual reset function. If your
application uses SIGUSR2 itself, you may wish to disable this, although
it should only be significant when the SerialTracking configuration is
enabled, as then the tracking is done by the main display process. The
default value is 1.
- void CAVESetReadLock(CAVELOCK lock)
- Sets a CAVE lock to indicate that the calling process will be reading
the associated shared data. While the read lock is set, any number of other
processes may also obtain read locks, but any processes requesting write
locks will be blocked until all the read locks are released (by CAVEUnsetReadLock()).
- void CAVESetWriteLock(CAVELOCK lock)
- Sets a CAVE lock to indicate that the calling process will be writing
the associated shared data. While the write lock is set, no other process
may obtain a read or write lock on the given CAVE lock. The write lock
is released by CAVEUnsetWriteLock().
- void CAVEUnsetReadLock(CAVELOCK lock)
- Releases a read lock which was set by CAVESetReadLock(). This
reduces the count of readers by one; if the count reaches 0, a process
waiting to set a write lock may then be allowed through.
- void CAVEUnsetWriteLock(CAVELOCK lock)
- Releases a write lock which was set by CAVESetWriteLock(). If
other processes are waiting to set a read or write lock on this lock, one
of them will then be allowed through.
- void *CAVEUserSharedMemory(int size)
- Creates a shared memory arena which can be used by your program. The
argument is the size of the arena in bytes. The return value is a pointer
to the arena which can be passed to amalloc in order to allocate space
from it (be aware that amalloc requires some extra space for overhead -
a few hundred bytes of general overhead, plus 16 bytes per amalloc'ed chunk
of memory). This function should be called before CAVEInit, so that all
processes will have access to the shared memory.
- char * CAVEWallName(CAVE_WALL_ID wall)
- Returns a string containing the name corresponding to the given wall
ID. For example, CAVEWallName(CAVE_FRONT_WALL) will return "front".
- void CAVEWallTransform(void)
- Sets up a transformation based on the calling process's wall. This
transformation will make the origin coincide with the lower left corner
of the wall, with the X and Y axes aligned with edges of the wall. It can
be used to draw objects directly on the wall. CAVEWallTransform()
affects both the ModelView and the Projection matrices, so if you wish
to preserve the old transformation before calling it, you must push and
pop both of these matrices.
- void CAVEWandTransform(void)
- Sets up a transformation using the wand's tracking data, which can
be used to position an object at the same location and with the same orientation
as the wand.
The transformation is relative to CAVE tracker coordinates; this function
should be called with no transformations active other than that initialized
by the CAVE library.
- Display * CAVEXDisplay(void)
- Returns the X Windows display pointer for the calling process's rendering
window. This should only be called from a display process. This function
is only available in the OpenGL CAVE library.
- XVisualInfo * CAVEXVisualInfo(void)
- Returns an XVisualInfo pointer for the calling rendering process's
window's X visual. This function is only available in the OpenGL CAVE library.
- Window CAVEXWindow(void)
- Returns a pointer to the X window being used by the calling rendering
process. This function is only available in the OpenGL CAVE library.
6.5 Environment Variables
There are two Unix environment variables which can be used to customize
the behavior of CAVE programs. They are:
- CAVE_HOME
- This defines the top-level directory containing the CAVE distribution;
the default directory, if CAVE_HOME is not set, is /usr/local/CAVE. The
library looks under this directory for the etc/ directory, which contains
the system-wide configuration files, and for the bin/ directory, which
contains the mplock and mpunlock
commands.
- CAVEDEBUGCONFIG
- Normally, CAVEConfigure() prints an abbreviated form of the final configuration
data to stderr when it has finished reading all the configuration files.
However, if CAVEDEBUGCONFIG is defined as "FULL", it will print
out a complete list of all the configuration options which will be used.
If this variable is defined as "OFF", the printout will not be
done at all. If this variable is defined as "VERBOSE", each configuration
option will be printed as it is processed.
6.6. Internal functions
This section describes some of the functions which are used internally
in the CAVE library. They are not called directly by a normal CAVE application.
However, they may be useful for developing other applications which need
some of the functionality of the CAVE library.
There are functions for reading configuration files, running the tracking
and networking processes, and getting the off-axis projection matrices
for CAVE walls.
- void CAVEConfigurationInit(int *argc,char **argv,char **appdefaults,CAVE_CONFIG_ST
*config)
- char *CAVEDebugConfigWallName(CAVE_WALL_ID wallnum)
- char *CAVEFullPathName(char *file)
- void CAVEGetProjection(CAVE_WALL_ID wall,CAVEID eye,float *frustum,Matrix
viewmat)
- void CAVETrackerStart(CAVE_CONFIG_ST *config)
- Must call CAVEConfigure()
- void CAVEUpdateSensors(void)
7. CAVE Simulation
7.1 Introduction
The CAVE Library provides options to simulate some or all of the hardware-specific
parts of the CAVE environment. This allows application developers to write
and test code on ordinary workstations, without requiring constant use
of the CAVE hardware.
There are three basic parts of the CAVE which can be simulated - the
tracker input, the wand input, and the immersive display. When running
a CAVE program, the configuration file (see Section
9) can be used to select the simulator mode for these options (note
that the "Simulator y" option is available as a shorthand method
of selecting all simulator options at once). The simulated tracking and
wand use the keyboard and mouse for controls; the simulated display provides
a perspective view, not limited to a single wall, and also an outside-the-CAVE
third-person view.
7.2 Simulated tracking
Simulated tracking is selected by the configuration option "TrackerType
simulator". The controls for moving the simulated head and wand are
given below.
7.2.1 Head Controls
The simulated user's head can be moved and rotated within the CAVE using
the arrow keys. Note that the head is restricted to remain within the confines
of physical CAVE. The commands to control the head are:
- LEFT_ARROW ............ Move left
- RIGHT_ARROW ........... Move right
- UP_ARROW .............. Move forward
- DOWN_ARROW ............ Move backward
- SHIFT + UP_ARROW ...... Move up
- SHIFT + DOWN_ARROW .... Move down
- ALT + LEFT_ARROW ...... Rotate left
- ALT + RIGHT_ARROW ..... Rotate right
- ALT + UP_ARROW ........ Rotate up
- ALT + DOWN_ARROW ...... Rotate down
- P .......... Reset head and wand to initial positions
7.2.2 Wand Controls
The wand is controlled using the mouse. Moving the mouse while holding
down the appropriate key will move or rotate the wand. As with the head,
the wand is restricted to stay inside the CAVE. When the user's head is
moved, the wand is moved with it. If more than one wand is being simulated
(using the SimulatorNumWands configuration option), only one wand
at a time may be controlled; the wand to control is selected using the
F keys (i.e. F1, F2, etc.).
The wand movement controls are as follows:
- CTRL + mouse movement ....... Move wand left/right/forward/back
- SHIFT + mouse movement ...... Move wand left/right/up/down
- ALT + mouse movement ........ Rotate wand left/right/up/down
- < and > .......... Roll wand (rotate about Z)
- HOME ....... Reset wand to be in front of user
- F1/F2/F3/... ................ Select wand 1/2/3/... as the current
wand being controlled.
7.3 Simulated wand controls
The simulated wand controls (buttons & joystick) are selected by
the configuration option "Wand simulator".
Pressing the mouse buttons corresponds to pressing the wand buttons.
Holding down the spacebar while moving the mouse controls the joystick
values. Note that the joystick controls set the X and Y values based on
the current position of the mouse on the screen, rather than the mouse's
relative movement (i.e. the top of the screen is Y=1.0, etc.). The joystick
is reset to (0,0) when the spacebar is released.
7.4 Simulated display
The simulated display is selected by using the "simulator"
wall (or "simulator1" or "simulator2") in the Walls
configuration option.
There are three display modes for the simulator wall. In mode 0, it
displays what would be rendered on one of the CAVE walls; in mode 1, it
displays a normal perspective view of the application's environment from
the position of the user's head; and in mode 2, it displays a third-person
view showing the user inside the CAVE. The simulator views can also show
the position of the user's head and of the wand, the current frame rate,
and the outline of the physical CAVE, and can black-out the parts of the
scene which would not be visible due the lack of right, back, and ceiling
walls.
The keyboard controls for these options are:
- 0 ...... Switch to "wall-view" mode
- 1 ...... Switch to user centered Perspective mode
- 2 ...... Switch to Outside the CAVE mode
- D .......... Switch to "Desk mode" (for outline &
blackout)
- C .......... Switch to "CAVE mode" (for outline &
blackout)
- T .......... Toggle timing (frame rate) display
- W .......... Toggle display of wand
- U .......... Toggle display of user (head)
- INSERT ..... Toggle display of CAVE/Immersadesk outline
- DEL ........ Toggle blackout of right, rear, and ceiling walls
- H .......... Print help text
When in wall-view mode (mode 0), the following keys select which wall's
display is rendered:
- F ........ front wall
- L ........ left wall
- B ........ floor ("bottom")
- R ........ right wall
- D ........ Immersadesk (screen7)
When using the outside-the-CAVE view, you can move the viewpoint around
with the following controls:
- KEYPAD ARROWS (2,4,6,8) .... Rotate the viewpoint
- KEYPAD -/+ ................. Zoom in/out
- KEYPAD 5 ................... Reset the viewpoint
8. Supporting software
There are several auxiliary programs which are used either by the CAVE
library or for testing the CAVE hardware. These programs can be found in
/usr/local/CAVE/bin.
- mplock
- mpunlock
- These programs will isolate and unisolate CPUs on the system. The arguments
are the numbers of the CPUs which are to be isolated/unisolated. If the
CPULock configuration option is set, mplock will be run by
the CAVE library on startup, and mpunlock will be run when the CAVE
exits. These programs are separate from the CAVE library because CPU isolation
requires superuser privileges; hence, the mplock and mpunlock
binaries must be owned by root and have their setuid permissions bit set.
- vss
- The sound server. vss must be running on the audio server machine
(whose IP address is given in the configuration file) before a CAVE program
starts. See the CAVE
Audio Library manual for more information.
- testpattern [cavesize] [pixel-xdim] [pixel-ydim]
- This program generates test patterns used for aligning the CAVE projectors
and matching colors between screens. It is intended to be run when the
display is in 1025x768 stereo video mode. The first optional argument is
the size of the CAVE (in feet); the default is 10'. The second and third
arguments are the resolution of the display, if other than 1025x768. The
different patterns are selected using the number keys (1, 2, 3, and 4).
Pattern 1 is a grid of 6"x6" squares, with diagonals and circles,
and an "L" in the leftbuffer and "R" in the rightbuffer.
There are diagonals and circles for both the full screen and for 90% of
the screen height (for the 10'x9' walls). Pattern 2 displays colorbars
running both vertically and horizontally. Pattern 3 is the same as pattern
2, except flipped horizontally; this is meant for the right wall. Patterns
4 & 5 are the same as patterns 1 & 2, but rotated 45 degrees; these
are intended for the setup of the ARPA Enterprise CAVE's floor.
- cavevars
- This is a basic confidence test for the CAVE library and hardware.
It displays the values of all the CAVE library's global variables on the
front wall, left wall, and floor. The values include the tracker data,
the eye positions derived from the tracker data, the status of the wand
buttons & joystick, and the timing information. The string "Left
Eye" is displayed in the left buffer, and "Right Eye" in
the right buffer. A set of X/Y/Z axes are displayed at the wand position
and at the head position (using the CAVE library tracker vector macros).
To exit the program, press Escape.
- scraminit
- scraminit is derived from Systran's Scramnet diagnostics program.
It merely initializes the board without any interaction. This program must
be run once, whenever the system is rebooted, before other programs can
use Scramnet.
- trackd
- trackd is a tracking daemon, which can be used with the 'daemon'
options for the TrackerType and Wand configuration. It supports the Flock
of Birds and Spacepad trackers, and the PC based wand. To read the Flock
tracker, run trackd with the flag -birds; to read the Spacepad,
run it with the flag -spacepad. To read the PC wand, run it with
the flag -controller <port>, where <port> is the name
of the serial port that the PC is attached to (e.g. /dev/ttyd4). When using
trackd with the wand, the serial port must not be configured
for a dial/button box.
9. CAVE Configuration File
The CAVE configuration file lists a number of setup options for the
CAVE which may change, but which would not normally be set by your program.
These include such things as which walls to use, and offsets for the physical
location of the tracker devices. When a CAVE program starts, the function
CAVEConfigure will read the configuration file and save the information
in a global record used by the various CAVE library functions. The default,
system wide configuration file /usr/local/CAVE/etc/cave.config is read
first. After reading this, CAVEConfigure will look for the file /usr/local/CAVE/etc/HOST.config,
where HOST is the machine name, as returned by gethostname().
Next, the file .caverc in your home directory is read, followed by the
file .caverc in the current directory. Any entries in one file will override
the settings from the files which were read earlier. This means that your
.caverc file(s) should only contain those values which you wish to change
from the default; most of the values, such as those for the trackers, should
only be specified in the system configuration files.
The configuration file is a text file with one configuration setting
per line. Each setting consists of a keyword followed by one or more values
for that configuration variable. Lines beginning with # are comments. The
parsing of keywords by CAVEConfigure is case-insensitive. All options which
specify linear measurements should have their units given at the end of
the line; the units that may be used are inches, feet, centimeters, and
meters; if no units are given, feet are assumed. The configuration options
that use units are: InterocularDistance, HeadSensorOffset, WandSensorOffset,
TransmitterPosition, Origin, CAVEWidth, CAVEHeight, SimulatorView,
and ProjectionData. The possible keywords and their meanings are:
- ActiveSensors <sensorID> <sensorID> ...
- Lists which sensors are considered to be active. This can be used to
disable certain tracker sensors by telling the library to ignore them.
The tracker device drivers will typically read data from all the sensors
which a tracker may have; the library, however, will only copy the data
from those which are listed as active; all other sensor data structures
will be filled in with the DefaultTrackerPosition and DefaultTrackerOrientation.
The <sensorID>'s given here are the indices in the CAVE sensor array;
i.e. ID 0 is the head, ID 1 is the wand, etc.
- AppDistribution <method>
- Selects the communication method to use for distributed CAVE function
calls made by the application. This can be different from the distribution
method used for the library internals (selected by Distribution).
The possible values for <method> are the same as for Distribution,
below. If AppDistribution is not specified, it defaults to the same
value as Distribution.
- BirdsHemisphere <hemisphere>
- Specifies which hemisphere to have the Flock-of-Birds tracker use.
hemisphere should be one of "lower", "upper",
"front", "aft", "left", or "right".
The default is "lower".
- BirdsSensors <headsensor> <wandsensor> ...
- Specifies which Flock of Birds sensors to read. The arguments are the
numeric ID's of the sensors, as reported by the tracker. The sensors will
be stored in the CAVESENSOR list in the order given here; i.e. the first
sensor listed will be used for the head, the second for the wand, etc.
The default values are "2 3".
- BirdsTransmitter <id>
- Gives the numeric ID of the Flock of Birds transmitter. The default
is 1.
- Calibration y|n
- Whether or not to use calibration for the tracker positions.
- CalibrationFile <filename>
- The name of the file containing the tracker calibration data.
- CAVEConfig <filename>
- Gives the name of another configuration file to read. The file is read
at the point that the CAVEConfig is encountered. If filename
is not an absolute path, the file is first searched for in the current
directory, then in the user's home directory, and finally in /usr/local/CAVE/etc
(or wherever $CAVE_HOME points). Only the first
instance of the file to be found will be read.
- CAVEHeight <height> <units>
- The height of the physical CAVE. This is only used in calculating the
projection for the original CAVE walls (front, left, right, floor, ceiling,
wall).
- CAVERotate <axis-X> <axis-Y> <axis-Z> <angle>
- Applies a fixed rotation to the CAVE within the virtual space. The
rotation is applied to the tracking data that is read, and to the projection
data (the screen corners) for each wall (except for HMD-type projections).
(<axis-X>,<axis-Y>,<axis-Z>) is the axis of the rotation;
<angle> is the angle of rotation in degrees.
- CAVERotationMatrix <m00> <m01> <m02> <m10>
<m11> <m12> <m20> <m21> <m22>
- Defines a CAVE rotation using a 3x3 matrix, instead of an axis and
angle.
- CAVEScale <scalefactor>
- An amount to scale the size of the CAVE by. All tracking and projection
data will be scaled by this factor, so the effect will be to produce a
view that looks like the virtual world has been scaled.
- CAVETranslate <xTrans> <yTrans> <zTrans>
- Applies a fixed translation to the CAVE within the virtual space. The
translation is applied to the tracking data that is read, and to the projection
data (the screen corners) for each wall (except for HMD-type projections).
- CAVEWidth <width> <units>
- The width of the physical CAVE. This is assumed to be the depth as
well. This is only used in calculating the projection for the original
CAVE walls (front, left, right, floor, ceiling, wall).
- ColorMask <wall-name> <eye(s)> <colors>
- Specifies which color channels are to be used when drawing a given
view. <wall-name> and <eye(s)> specify the view to for this
mask applies; <wall-name> can be any of the possible walls; <eye(s)>
can be 'left', 'right', 'both', or '*' (an alias for 'both'). <colors>
is a string consisting of one or more of the letters "R", "G",
and "B", indicating which color channels to use. i.e. "R"
indicates just the red channel, "G" indicates just the green
channel, "RB" indicates both the red and blue channels, etc.
The default ColorMask for all views is "RGB".
Note that if the left and right eye views overlap within the same buffer
(i.e. StereoBuffer is 'n' and they do not have disjoint viewports), the
ColorMask operation will not work properly if an IrisGL application calls
czclear() as it ignores the color writemask. To avoid this, you
must clear the color and depth buffers separately. This problem also occurs
in OpenGL on Reality Engines, when calling glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT).
- ControllerDaemonKey <key>
- Gives the key number for the shared memory segment which is being used
by the controller daemon process.
- CPULock y|n
- Whether to "lock" the CPUs or not. If this is 'y', each CAVE
process will be forced to run on a different, isolated CPU. The isolation
will prevent other processes on the system from using these CPUs. CPU 0
will not be isolated; if there are not enough processors for all the CAVE
processes, the remainder will all share CPU 0. CAVEExit will un-isolate
the CPUs. This requires the programs mplock
and mpunlock (in /usr/local/CAVE/bin). If
your CAVE program crashes while using this option, you should run mpunlock
manually to un-isolate the processors.
- DefaultTrackerOrientation <elevation> <azimuth> <roll>
- The default values to be used for a tracker's orientation. These values
are used when no tracker is selected, or for sensors which are not being
tracked.
- DefaultTrackerPosition <x> <y> <z>
- The default values to be used for a tracker's position. These values
are used when no tracker is selected, or for sensors which are not being
tracked.
- DisplayMode <mode>
- Determines whether the display will be stereoscopic or monoscopic.
<mode> can be either "mono", "stereo", "oldstereo",
or "anaglyphic". "stereo" selects the newer stereo
buffer method; "oldstereo" selects the older STR_RECT style stereo.
"anaglyphic" selects a red/blue stereo display - the left eye
view is drawn in the red bitplanes, the right eye view in the blue &
green bitplanes; this mode will not work if an application clears the color
and depth buffers simultaneously (via czclear() or the equivalent
glClear() mode) - separate clear calls must be used for the two
buffers.
- Distribution <method>
- Selects the communication method to use for a distributed CAVE. If
distribution is not to be used, <method> should be "none".
The distribution methods available are "scramnet" and "tcp".
"scramnet" distribution uses Scramnet reflective memory (or ordinary
shared memory when Scramnet is disabled). "tcp" distribution
uses TCP/IP sockets.
- DistribID <id>
- The ID number for a distributed CAVE node. This should be in the range
0 to N-1, where N is the number of distributed nodes. The node with ID
0 is the master; it must be started before any slave nodes.
- DistribNodes <number>
- The number of nodes that the distributed CAVE is composed of. All current
distribution methods support only 2 nodes.
- DistribTCPMaster <hostname>
- The network host name of the master node when using TCP/IP distribution.
- DistribTCPPort <port-number>
- The port number to use for TCP/IP distribution communications. <port-number>
should be greater than 1024, and different from any standard service port
numbers (see /etc/services).
- Exec <command>
- Executes a shell command. <command> is passed to the shell via
a system() call. The command is executed as soon as it is encountered
during the parsing of the configuration files.
- FilterBirds y|n
- If this flag is "y", the Flock-of-Birds tracker's hardware
filtering option will be enabled.
- FilterBirdsParameter <param>
- Specifies the argument for the Flock of Birds hardware filtering command.
<param> is an integer that defines which filters are to be used;
the possible values are described in the Ascension manual under CHANGE
VALUE / FILTER STATUS.
- GangSwap y|n
- If this option is "y", the Reality Engine's hardware swapready
lines will be used to synchronize the multiple displays in a distributed
CAVE. This option only works with IrisGL.
- HeadSensorOffset <X-offset> <Y-offset> <Z-offset>
<units>
- Offset values from the position of the head sensor to the point between
the user's eyes. The offset is added to the position reported by the head
tracker to yield the position that the CAVE library will report.
- HeadSensorRotation <axis-X> <axis-Y> <axis-Z> <angle>
- The rotation of the physical head sensor relative to the sensor as
reported by the library. This is defined by an axis vector and an angle
of rotation around that vector. The angle is in degrees.
- HeadSensorRotationMatrix <m00> <m01> <m02> <m10>
<m11> <m12> <m20> <m21> <m22>
- Defines the head sensor rotation using a 3x3 matrix, instead of an
axis and angle.
- HideCursor y|n
- Whether or not to blank the cursor when in the CAVE windows.
- InterocularDistance <distance> <units>
- The distance between the user's eyes. 2.75 inches is the default value.
- Network <method>
- What style of networking to use. <method> can be one of "mcast",
"udp", or "none". If networking is enabled (i.e. <method>
is not "none"), a separate process will be started by CAVEInit
to broadcast and receive tracking and application data. For the "mcast"
<method>, UDP multicasting is used; for "udp", ordinary
non-multicast UDP/IP is used. In "mcast" mode, CAVE networking
packets are broadcast to the multicast group address given by NetworkAddress.
In "udp" mode, networking packets are sent to the host specified
by NetworkUDPHost, which can be either a another CAVE, or a server which
re-distributes the packets to other CAVEs.
- NetworkAddress <mcast-ip-address>
- The numeric IP address of the multicast group which will be used for
broadcasting CAVE data, when the networking method is "mcast".
All CAVE applications running on the local multicast network using this
address will share data; different applications on the same network should
use different addresses to keep their data separate.
- NetworkAppPort <port-number>
- The port number to use for broadcasting application data (for the functions
CAVENetSend and CAVENetReceive). <port-number> should
be greater than 1024, and different from any standard service port numbers
(see /etc/services). If NetworkAppPort is not specified, it defaults
to NetworkPort+1.
- NetworkCPUHog y|n
- Whether or not to the networking process should run as fast as possible.
Default value is 'n', which causes the process to sleep briefly (10 milliseconds)
whenever no new data is being sent or received, to limit its CPU use. If
set to 'y', the process will constantly check for new data to send or receive
without pausing.
- NetworkMaxUsers <num-users>
- The maximum number of users to expect to receive data from. This defines
the size of the CAVEUser array. The default value is 32.
- NetworkPort <port-number>
- The port number to use for broadcasting tracking data. <port-number>
should be greater than 1024, and different from any standard service port
numbers (see /etc/services).
- NetworkTTL <ttl>
- The 'time-to-live' for multicast networking packets. This can be used
to control how far packets will spread through gateways and multicast tunnels
(see mrouted documentation for details).
- NetworkUDPHost <hostname>
- The name of the remote host to communicate with when using the UDP
networking method.
- NetworkUpdateInterval <interval>
- Controls how frequently the networking process will broadcast tracking
packets. <interval> is the number of seconds between broadcasts (ie
a value of .05 will broadcast new data 20 times a second).
If <interval> is negative, the local tracking data will never be
broadcast. This provides a 'stealth' mode where the local CAVE sees all
other CAVEs, but is not visible to them.
- Origin <left-distance> <floor-distance> <front-distance>
<units>
- Origin of the CAVE coordinate system. This is specified as the distance
from the three walls to the origin. For the 10' CAVE, these values are
"5 0 5 feet". This is only used in calculating the projection
for the original CAVE walls (front, left, right, floor, ceiling, back).
- ProjectionData <wall-name> <eye(s)> <type> <lower-left
x y z> <upper-left x y z> <lower-right x y z> <units>
- Defines the type of projection and the corners of the projection plane
for a given wall/eye view. This is used only by the general-purpose "screen[0-7]"
walls. <wall-name> is the name of the wall that is being defined
(screen0, screen1, etc.). <eye(s)> indicates which eye-views this
data is for; the possible values are 'left', 'right', 'both', or '*' (an
alias for 'both'). <type> defines the type of display being used
- either 'wall' or 'hmd'. A 'wall' display is one which is fixed in space,
such as a CAVE or ImmersaDesk screen; an 'hmd' display is a one that is
coupled to the tracked user's head.
The remainder of the data define the projection plane by specifying the
locations of the lower left, upper left, and lower right corners. For a
'wall' display, the corner positions are given in tracker coordinates.
For an 'hmd' display, the three points specify the projection plane in
eye-space coordinates; eye-space coordinates are defined as having the
eye at the origin, with the axes aligned with the user's head - the Z axis
points directly back, the Y axis points up, the X axis points right.
This is used to compute the perspective projection for <wall-name>,
and so must be given if one of the "screen" walls is active.
- Putenv <string>
- Performs a putenv(string) when read, allowing environment variables
to be set from the configuration. e.g. "Putenv SOUNDSERVER=cavesound".
- Scramnet y|n
- Indicates whether Scramnet memory is to be used. If this flag is 'n',
Scramnet is simulated using normal Unix shared memory (see also the "SimScramKey"
option), allowing programs to run without requiring an actual Scramnet
card. Scramnet memory (real or simulated) is used by CAVEScramnetMalloc(),
"Distribution scramnet", and the Scramnet tracker and wand.
- ScramnetDevices <memoryDevice> <registerDevice>
- The file names of the VME devices which correspond to Scramnet memory
and Scramnet control registers.
- ScramnetMemBase <baseAddress>
- The base address of Scramnet memory, for mmap()ing the Scramnet device.
This value can be found in the Scramnet software's configuration file (cfg/scrcfg.dat).
- ScramnetMemSize <size>
- The size of Scramnet memory in bytes. This value can be found in the
Scramnet software's configuration file (cfg/scrcfg.dat).
- ScramnetPrefix <prefix-num>
- A 16-bit prefix added to the IDs of all Scramnet memory segments allocated
by the CAVE library. This allows unrelated applications (such as multiple
CAVE systems) to share a single Scramnet network, by using different prefixes.
- ScramnetRegBase <baseAddress>
- The base address for mmap()ing the Scramnet control registers. This
value can be found in the Scramnet software's configuration file (cfg/scrcfg.dat).
- ScramnetRegSize <size>
- The size of the Scramnet control registers' area of memory. This value
can be found in the Scramnet software's configuration file (cfg/scrcfg.dat).
- SerialTracking y|n
- Indicates whether tracking should be done serially or in parallel.
If SerialTracking is enabled, one of the rendering processes will read
the tracker and wand devices; if it is disabled (the default), a separate
process is used to read the devices. In general, serial tracking should
only be used with the simulator tracker, where a separate process can put
too much of a load on the X server and slow up the rest of an application,
or with the daemon or Scramnet trackers, which do not require much CPU
processing.
- SimScramKey <key>
- The key number for the shared memory segment created when Scramnet
is simulated (by "Scramnet n"). If <key> is 0, private
shared memory is used. If it is non-zero, separate programs can connect
to the simulated Scramnet; this can be used to test distributed CAVE programs
on a single machine.
- Simulator y|n
- Shorthand option for selecting full simulator mode. Using the configuration
"Simulator y" is equivalent to specifying the options "Walls
Simulator", "WallDisplay simulator -1 window", "Tracking
y", "TrackerType simulator", "Wand simulator",
"WandSensorOffset 0 0 0", "WandSensorRotation 1 0 0 0",
"HeadSensorOffset 0 0 0", "HeadSensorRotation 1 0 0 0",
"TransmitterOffset 0 0 0", "TransmitterRotation 1 0 0 0",
"UseCalibration n", "SerialTracking y", "Distribution
none", and "AppDistribution none". NB: Saying "simulator
n" will merely set the flag CAVEConfig->Simulator to 0; it will
not undo any other effects of a previous "simulator y".
- SimulatorJoystickControl <device>
- Specifies the key to press to activate the joystick control when using
the simulator wand. <device> is the name of a device as given in
<gl/device.h> (e.g. "CAPSLOCKKEY"). The default is the
spacebar.
- SimulatorNumWands <num>
- The number of wand sensors to simulate, when using simulator tracking.
The default is 1.
- SimulatorView <width> <height> <distance> [<units>]
- The viewing parameters which define the projection frustum for the
simulator display. <width> and <height> are the size of the
screen; <distance> is the distance of the viewer's head from the
screen.
- StereoBuffer y|n
- Indicates whether or not to use quad-buffered stereo. If this flag
is 'y', the CAVE windows will be opened with stereo buffering enabled.
All left eye views will be drawn in the left buffers, and right eye views
in the right buffers. If this flag is 'n', both left and right eye views
will be drawn in the same buffer.
- SyncBirds type1|type2|n
- If this flag is "type1" or "type2", the Flock-of-Birds
tracker will be made to synchronize itself with the projectors, to prevent
any interference. "type1" synchronization runs the transmitter
at the same frequency as the projectors; "type2" runs the transmitter
at twice the frequency of the projectors. This requires additional hardware
connecting the Birds and the projector.
- TrackerBaud 19200|9600|...
- Baud rate for the tracker serial device. 19200 is the default.
- TrackerDaemonKey <key>
- Gives the key number for the shared memory segment which is being used
by the tracker daemon process.
- TrackerPort <portname> [<port2name>]
- Name of the serial port(s) that the trackers are attached to. <portname>
should be something like /dev/ttym2. The Logitech tracker uses a second
serial port for the wand tracker; <port2name> identifies this port.
- TrackerType <name>
- Which type of tracking hardware is being used. <name> should
be one of "birds", "spacepad", "logitech",
"daemon", "boom", "mouse", "simulator",
"spaceball", or "none". "birds" selects the
Ascension Flock-of-Birds magnetic tracker. "spacepad" selects
the Ascension Spacepad tracker. "logitech" selects the Logitech
ultrasonic tracker. "daemon" selects the tracker daemon method,
where tracking is done by a completely independent program, communicating
with the library through standard SysV shared memory (see the TrackerDaemonKey
configuration). "boom" selects the library's built-in BOOM tracking
code; this has only been tested on NCSA's older BOOM2, and may not work
on other hardware versions. "mouse" selects a simple mouse-controlled
tracking system, which can be useful for testing purposes. "simulator"
selects a simulated tracking system that uses keyboard and mouse controls
(see Section 7.2). Since both the tracker
positions and the wand controls are handled by the tracker process, "TrackerType
none" can be used to have this process only check the wand controls.
Note: the spaceball tracker is not available in the OpenGL version
of the library.
- Tracking y|n
- Whether or not to run the tracker process. If tracking is disabled,
the head and wand are assigned fixed default positions (set by DefaultTrackerPosition
and DefaultTrackerOrientation), and all the buttons and joystick values
are set to 0.
- TransmitterOffset <X-offset> <Y-offset> <Z-offset>
<units>
- The position of the transmitter in CAVE coordinates. This is used to
adjust the values returned by the trackers.
- TransmitterRotation <axis-X> <axis-Y> <axis-Z> <angle>
- The orientation of the transmitter in the CAVE space. This is defined
by an axis vector and an angle of rotation around that vector. The angle
is in degrees.
- TransmitterRotationMatrix <m00> <m01> <m02> <m10>
<m11> <m12> <m20> <m21> <m22>
- Defines the transmitter rotation using a 3x3 matrix, instead of an
axis and angle.
- Units <units>
- What units to use for the CAVE coordinates. <units> should be
"feet", "meters", "inches", or "centimeters".
Tracking data will be reported in the given units, and the graphics projections
will be in those units. "feet" is the default.
- VerboseConfig y|n
- Toggles verbose configuration debugging on or off. When in verbose
mode, each configuration option is printed to stderr as it is read.
- Viewport <wall-name> <eye(s)> <min-x> <max-x>
<min-y> <max-y>
- Defines the viewport within a wall's window to be used for an eye's
view. The geometry of a wall's window is specified by WallDisplay; the
Viewport option allows different sub-sections of the full window to be
used for the different eye's views. <wall-name> is the name of the
wall that the viewport is for (front, screen0, etc.). <eye(s)> indicates
which eye-views this viewport is for; the possible values are 'left', 'right',
'both', or '*' (an alias for 'both'). [<min-x>,<max-x>] and
[<min-y>,<max-y>] describe the range of the viewport in X and
Y; their values should be between 0 and size-1 inclusive, where
size is the X or Y size of the window. A viewport range of "-1
-1 -1 -1" will tell the library to use the full window; this is the
default value.
NB: The Viewport option does not apply to displays with "window"
geometry (see WallDisplay).
- ViewportMask <wall-name> <eye(s)> <filename>
- Defines a mask file to be used for blacking-out portions of the display.
<wall-name> and <eye(s)> specify the view to which this mask
should be applied; <wall-name> can be any of the possible walls;
<eye(s)> can be 'left', 'right', 'both', or '*' (an alias for 'both').
<filename> is the name of a separate file which contains the mask
information. A mask file is a text file which contains a list of polygons;
the polygons should cover the area of the display which is to be blacked
out. The first line of the mask file should give the number of polygons.
The polygons are then listed, one per line. A polygon list consists of
the number of vertices, followed by a list of vertex positions, where each
position is a pair of comma-separated coordinates. The coordinate system
for the vertices ranges from (0,0) (lower left corner of the viewport)
to (1,1) (upper right corner of the viewport). For example, a mask file
to black-out the lower right and upper left corners of the display would
look like:
2
3 0,1 .5,1 0,.5
3 1,0 1,.5 .5,0
- WallDisplay <wall-name> <pipe#> [<window-geometry>]
- Describes where a given wall's window will be displayed on the workstation.
<wall-name> can be one of "front", "left", "right",
"floor", "back", "ceiling", "screen0",
..., "screen7", "simulator", "simulator1",
or "simulator2".
<pipe#> is the number of the graphics pipe used by the wall. Pipe
number 0 corresponds to display :0.0, number 1 to :0.1, etc. If <pipe#>
is -1, the wall will inherit your shell's DISPLAY variable, rather than
redefining it. Also, an X display (e.g. "evl:0.0") can be specified
in place of a pipe number; this can be used to display the wall on a remote
machine in place of the local hardware.
<window-geometry> defines the area on the display for the window;
it is given in the format "XDIMxYDIM+XOFFSET+YOFFSET" (e.g. 512x512+300+100).
If the string "window" is given instead of a size and offsets,
the wall will be displayed in a normal, bordered window which can be moved
and resized. If no geometry is given, it will default to the full managed
area of the screen.
- WallExitCommand <wall> <command>
- Specifies a shell script or program which is to be run before the given
wall exits (when CAVEExit() or CAVEHalt() is called). The
command will be executed by the wall's display process, after the window
has been closed.
- WallEyes <wall-name> both|left|right
- Indicates for which eyes a view should be rendered on the given screen.
The options are "both", "left", and "right".
The normal default value is "both". If "DisplayMode"
is mono, then any walls for which both eyes have been selected will be
automatically switched to left eye only. <wall-name> should be one
of the allowed wall names listed under "Walls" (below).
- WallInitCommand <wall> <command>
- Specifies a shell script or program which is to be run when the given
wall is initialized. The command will be executed by the wall's display
process, before the window is created, with the DISPLAY environment variable
set to the wall's display. This can be used for automatically changing
the video mode of a pipe.
- Walls <wall> <wall> ...
- Lists which walls are active. <wall> can be one of "front",
"left", "right", "floor", "back",
"ceiling", "screen0", "screen1", ..., "screen7",
"simulator", "simulator1", or "simulator2".
The display information (see WallDisplay) must be provided for a wall to
be used (the system config file should already contain that information
for all walls that are physically available).
The "simulator" wall selects the simulator-style display (see
Section 7.4. The "simulator1"
wall is a simulator display that is always in viewing mode 1; the "simulator2"
wall is always in mode 2.
The "screen#" walls are intended for the Immersadesk or any other
fixed screen display that does not correspond to one of the canonical six
walls. If one is selected, the corresponding "ProjectionData"
configuration data must also be given.
- Wand <wand-type>
- The type of wand being used. <wand-type> should be one of "mouse",
"PC", "logitech", "daemon", "simulator",
"custom", or "none". This determines what controls
are read (buttons/joystick). The "mouse" wand will read the three
mouse buttons. "PC" indicates the PC-based wand with three buttons
and a pressure-sensitive joystick. The "logitech" option is for
the Logitech flying mouse; it should only be used in conjunction with "TrackerType
logitech". The "daemon" option is for use with an independent
daemon program (such as trackd), which communicates
with the library through standard SysV shared memory (see the ControllerDaemonKey
configuration). The "simulator" option will use the mouse and
spacebar to simulate the PC wand's buttons and joystick. The "custom"
option is used along with the "WandButtons" and "WandValuators"
configurations to define an arbitrary set of control devices for the wand.
- WandButtons <device1> <device2> ...
- Defines the button devices to read for a custom wand (see "Wand"
above). The devices should be GL device names, as defined in <gl/device.h>.
<device1> will be read for CAVEBUTTON1, <device2> for CAVEBUTTON2,
etc. Up to 16 buttons may be given.
- WandSensorOffset <X-offset> <Y-offset> <Z-offset>
<units>
- The offset from the location of the physical sensor attached to the
wand to the location which will be reported by the library for the wand.
- WandSensorRotation <axis-X> <axis-Y> <axis-Z> <angle>
- The rotation of the physical wand sensor relative to the sensor as
reported by the library. This is defined by an axis vector and an angle
of rotation around that vector. The angle is in degrees.
- WandSensorRotationMatrix <m00> <m01> <m02> <m10>
<m11> <m12> <m20> <m21> <m22>
- Defines the wand sensor rotation using a 3x3 matrix, instead of an
axis and angle.
- WandValuators <device0> <min0> <max0> <device1>
<min1> <max1> ...
- Defines the valuator devices to read for a custom wand (see "Wand"
above). The devices should be GL device names, as defined in <gl/device.h>.
<device0> will be read for CAVEController->valuator[0] (aka CAVE_JOYSTICK_X),
<device1> for CAVEController->valuator[1], etc. <min#> and
<max#> define the minimum and maximum values that will be returned
by the device itself; these values are then mapped to -1.0 to 1.0 when
stored in CAVEController->valuator[#]. Up to 16 valuators may be given.
10. Sample Programs
10.1. CAVE sample program 1
/* simple.c
/* A trivial CAVE demo program, demonstrating the most basic CAVE library
/* functions. This program just draws a red triangle in the front of the
/* CAVE. No interaction (outside of moving around), and nothing changes.
*/
#include <cave.h>
void simple_draw(void);
main(int argc,char **argv)
{
/* Initialize the CAVE */
CAVEConfigure(&argc,argv,NULL);
CAVEInit();
/* Give the library a pointer to the drawing function */
CAVEDisplay(simple_draw,0);
/* Wait for the escape key to be hit */
while (!getbutton(ESCKEY))
sginap(10);
/* Clean up & exit */
CAVEExit();
}
/* simple_draw - the display function. This function is called by the
CAVE library in the rendering processes' display loop. It draws a red
triangle 2 feet tall, 4 feet off the floor, and 1 foot in front of the
front wall (assuming a 10' CAVE). */
void simple_draw(void)
{
float vert1[3] = { -1, 4, -4},
vert2[3] = { 1, 4, -4},
vert3[3] = { 0, 6, -4};
cpack(0); clear(); zclear();
cpack(0xff);
bgnline();
v3f(vert1);
v3f(vert2);
v3f(vert3);
v3f(vert1);
endline();
}
10.2. CAVE sample program 2 (OpenGL)
#include <cave_ogl.h>
#include <GL/glu.h>
void init_shared_data(),gl_init_fn(),draw_fn();
/* Shared data */
float *x,*y,*z;
main(int argc,char **argv)
{
float vx,vy,vz;
CAVEConfigure(&argc,argv,NULL);
init_shared_data();
vx = (drand48()-0.5)/10.0;
vy = (drand48()-0.5)/10.0;
vz = (drand48()-0.5)/10.0;
CAVEInit();
CAVEInitApplication(gl_init_fn,0);
CAVEDisplay(draw_fn,0);
while (!CAVEgetbutton(CAVE_ESCKEY))
{ /* Bounce the ball around */
if (*x < -5) vx = fabs(vx);
else if (*x > 5) vx = -fabs(vx);
if (*y < 0) vy = fabs(vy);
else if (*y > 10) vy = -fabs(vy);
if (*z < -5) vz = fabs(vz);
else if (*z > 5) vz = -fabs(vz);
*x += vx;
*y += vy;
*z += vz;
sginap(1); /* Make this loop run about 100 iterations/second */
}
CAVEExit();
}
/* Get a shared arena, amalloc the shared variables, & initialize them */
void init_shared_data()
{
x = (float *) CAVEMalloc(sizeof(float));
y = (float *) CAVEMalloc(sizeof(float));
z = (float *) CAVEMalloc(sizeof(float));
*x = 0;
*y = 5;
*z = 0;
}
static GLUquadricObj *sphereObj;
/* initialize the graphics - define the lighting data */
void gl_init_fn()
{
float light_pos[] = { -5, 10, 5, 0 };
float mat_diffuse[] = { 0.6, 0.5, 0.1, 1 };
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
glEnable(GL_LIGHT0);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_diffuse);
sphereObj = gluNewQuadric();
}
/* draw the scene - draw a ball at (*x,*y,*z), and, if button 1 is pressed,
draw a smaller ball in front of the wand */
void draw_fn()
{
glClearColor(0.5, 1., 1., 0.);
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
glEnable(GL_LIGHTING);
glPushMatrix();
glTranslatef(*x,*y,*z);
gluSphere(sphereObj, 1.0, 8, 8);
glPopMatrix();
if (CAVEBUTTON1)
{
float wandPos[3],wandFront[3];
CAVEGetPosition(CAVE_WAND,wandPos);
CAVEGetVector(CAVE_WAND_FRONT,wandFront);
glPushMatrix();
glTranslatef(wandPos[0]+wandFront[0]*2,wandPos[1]+wandFront[1]*2,
wandPos[2]+wandFront[2]*2);
gluSphere(sphereObj, .25, 8, 8);
glPopMatrix();
}
glDisable(GL_LIGHTING);
}