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
Copyright 1996,1997 Electronic Visualization Laboratory, University of Illinois at Chicago
written by Dave Pape, Carolina Cruz-Neira, Marek Czernuszenko
TABLE OF CONTENTS
- 1. Purpose of the CAVE User's Guide
- 2. CAVE Description
- 3. CAVE Equipment
- 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. ImmersaDesk and Other Hardware
- 4.1. Immersadesk
- 4.2. Other Hardware
- 5. CAVE Programming
- 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. CAVE Library
- 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. CAVE Simulation
- 7.1. Introduction
- 7.2. Simulated tracking
- 7.3. Simulated wand controls
- 7.4. Simulated display
- 8. Supporting software
- 9. CAVE configuration files
- 10. Sample programs
- 10.1. CAVE sample program 1
- 10.2. CAVE sample program 2
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
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
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.
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.
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.
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.
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.
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.
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.
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.
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:
- User should sit on a chair while using Immersadesk.
Then he will tend to look up.
- Use CrystalEyes glasses with following
modification (see fig xx). Receiving microphones, are mounted on a
small plastic triangle which is attached to the glasses
under 45 degree angle. In this case, even when user bends
over the screen, receiving microphones are still
facing transmitter.
Figure 3: Logitech glasses modification
- Hand tracking: Logitech "flying mouse" is used
as a wand. It has 4 buttons - 3 in front, and 4th
on left and right side of the mouse. Notice that
you cannot point with this wand to the back, since
microphones, that are mounted in front of that mouse
will not face transmitter.
- Flock of Birds
Same as in the CAVE.
This page not written.
II. Software
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.
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
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.
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.
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.
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.
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.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.
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).
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
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.
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).
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.
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.
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 *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)
-
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.
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.
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.
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
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.
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.
9.1. Configuration options
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" or
"stereo". If DisplayMode is set to "mono", quad-buffered
stereo (see StereoBuffer below) will be disabled, and
any walls for which both eyes are selected (see WallEyes)
will be changed to only display the left eye view.
-
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",
"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.
-
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 X display used by the wall, e.g.
":1.0" or "kona:0.0".
If <pipe> is -1, the wall will inherit
your shell's DISPLAY variable, rather than redefining it.
<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.
9.2. Default Values
The default configuration state, defined in CAVEConfigure() before any files are read,
is:
ActiveSensors 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
AppDistribution none
BirdsHemisphere lower
BirdsSensors 2 3
BirdsTransmitter 1
Calibration n
CalibrationFile ""
CAVEHeight 10
CAVERotationMatrix 1 0 0 0 1 0 0 0 1
CAVEScale 1
CAVETranslate 0 0 0
CAVEWidth 10
ColorMask * * rgb
ControllerDaemonKey 9801
CPULock n
DefaultTrackerOrientation 0 0 0
DefaultTrackerPosition 0 5 0
DisplayMode mono
Distribution none
DistribID 0
DistribNodes 0
DistribTCPMaster ""
DistribTCPPort 0
FilterBirds n
FilterBirdsParameter 0
GangSwap n
HeadSensorOffset 0 0 0
HeadSensorRotationMatrix 1 0 0 0 1 0 0 0 1
HideCursor n
InterocularDistance 2.75 inches
Network none
NetworkAddress ""
NetworkCPUHog n
NetworkMaxUsers 32
NetworkPort 0
NetworkTTL 4
NetworkUDPHost ""
NetworkUpdateInterval 1
Origin 5 0 5
ProjectionData * * wall -5 0 -5 -5 10 -5 5 0 -5
Scramnet n
ScramnetDevices ""
ScramnetMemBase 0
ScramnetMemSize 131072
ScramnetPrefix 0
ScramnetRegBase 0
ScramnetRegSize 16
SerialTracking n
SimScramKey 0
Simulator n
SimulatorJoystickControl SPACEKEY
SimulatorNumWands 1
SimulatorView 10 7.5 2
StereoBuffer y
SyncBirds n
TrackerBaud 19200
TrackerDaemonKey 9800
TrackerPort ""
TrackerType none
TransmitterOffset 0 0 0
TransmitterRotationMatrix 1 0 0 0 1 0 0 0 1
Units feet
VerboseConfig n
Viewport * * -1 -1 -1 -1
WallDisplay *
WallExitCommand * ""
WallEyes * both
WallInitCommand * ""
Walls ""
Wand mouse
WandSensorOffset 0 0 0
WandSensorRotationMatrix 1 0 0 0 1 0 0 0 1
Note: As a special case, if CAVEConfigure() does not find any
files (cave.config, HOSTNAME.config, or .caverc), it will automatically execute a
"simulator y" configuration. This is for the convenience of people trying programs
on machines which have not been set up with the CAVE software.
/* 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();
}
#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);
}