CAVELib 3.2.1 User and Reference Guide

Transcription

CAVELib 3.2.1 User and Reference Guide
User and Reference Guide
April 2010 Edition
Mechdyne Corporation
I
CAVELib 3.2.1 User and Reference Guide
Table of Contents
1
Chapter 1 - CAVELib Programming
1.1 Introduction ................................................................................................................................... 1
...................................................................................................................................
1
1.2 Compiling a CAVELib
Program
.......................................................................................................................................................... 1
1.2.1 CAVELib Applications
2
1.2.2 W2K CAVELib..........................................................................................................................................................
Application Projects
Workspace
Project
Project Settings
Source Files
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
.........................................................................................................................................................
2
3
3
4
................................................................................................................................... 5
1.3 CAVELib Callbacks
................................................................................................................................... 5
1.4 Rendering
................................................................................................................................... 6
1.5 Interaction
1.5.1 Trackers
1.5.2 Controller
.......................................................................................................................................................... 6
.......................................................................................................................................................... 7
1.6 Navigation ................................................................................................................................... 7
................................................................................................................................... 8
1.7 Multi-Threading
.......................................................................................................................................................... 8
1.7.1 Shared Memory
.......................................................................................................................................................... 9
1.7.2 Data Synchronization
1.7.3 Program Flow .......................................................................................................................................................... 9
10
1.8 CAVELib On...................................................................................................................................
Clusters
...................................................................................................................................
13
1.9 Form of a Basic
CAVELib Program
..........................................................................................................................................................
13
1.9.1 Program Source
Code
..........................................................................................................................................................
15
1.9.2 Program Structure
Chapter 2 - Simulation
16
2.1 Introduction ................................................................................................................................... 16
................................................................................................................................... 16
2.2 Simulated Tracking
2.2.1 Head Controls.......................................................................................................................................................... 16
2.2.2 Wand Controls.......................................................................................................................................................... 17
...................................................................................................................................
17
2.3 Simulated Wand
Controls
................................................................................................................................... 17
2.4 Simulated Display
Chapter 3 - Sample Programs
19
...................................................................................................................................
19
3.1 CAVELib Sample
Program 1
...................................................................................................................................
20
3.2 CAVELib Sample
Program 2
Chapter 4 - Software Configuration
25
4.1 Introduction ................................................................................................................................... 25
25
4.2 Configuration...................................................................................................................................
Keywords
...................................................................................................................................
35
4.3 Legacy Configuration
Keywords
© 2010 enter value here
Contents
II
Chapter 5 - Hardware Configurations
37
5.1 i3D Structures................................................................................................................................... 37
5.1.1 Projectors and..........................................................................................................................................................
Mirrors
5.1.2 Stereo Glasses..........................................................................................................................................................
..........................................................................................................................................................
5.1.3 Stereo Emitters
..........................................................................................................................................................
5.1.4 Controller
..........................................................................................................................................................
5.1.5 Tracking Systems
5.1.6 Workstation ..........................................................................................................................................................
...................................................................................................................................
5.2 General Configuration
Notes
37
38
38
38
38
39
39
...................................................................................................................................
5.3 Basic Configuration
Display
...................................................................................................................................
5.4 Canonical Displays, CAVE and Box Format Displays
...................................................................................................................................
5.5 ImmersaDesk(TM)
/ Desk-Type Display
...................................................................................................................................
5.6 Holobench / Multi-Screen
Desk
5.7 Reality Center...................................................................................................................................
/ Curved Screen Display
39
..........................................................................................................................................................
5.7.1 Single Pipe Super
Desktop Setup
..........................................................................................................................................................
5.7.2 Three Pipe Super
Desktop Setup
..........................................................................................................................................................
5.7.3 Three Pipe Fixed
Projection Point Setup
...................................................................................................................................
5.8 Additional Configuration
Options for Clusters
44
45
46
5.8.1
5.8.2
41
42
43
44
48
..........................................................................................................................................................
48
Master Node Configuration
Settings
..........................................................................................................................................................
48
Slave Node Configuration Settings
Chapter 6 - Functions, Data Types, and Macros
49
6.1 Data Types ................................................................................................................................... 52
6.2
..........................................................................................................................................................
6.1.1 CAVE_WALL_ID
..........................................................................................................................................................
6.1.2 CAVEID
..........................................................................................................................................................
6.1.3 CAVE_SENSOR_ST
..........................................................................................................................................................
6.1.4 CAVE_CONTROLLER_ST
6.1.5 CAVENETID ..........................................................................................................................................................
..........................................................................................................................................................
6.1.6 CAVE_USER_ST
6.1.7 CAVELOCK ..........................................................................................................................................................
..........................................................................................................................................................
6.1.8 CAVECALLBACK
..........................................................................................................................................................
6.1.9 CAVE_ST
...................................................................................................................................
CAVELib Functions
52
52
52
53
53
53
53
53
53
54
..........................................................................................................................................................
54
6.2.1 Basic CAVELib
Functions
void CAVEConfigure(int
.........................................................................................................................................................
*argc,char **argv,char **appdefaults)
void CAVEDisplay(CAVECALLBACK
.........................................................................................................................................................
function,int num_args,...)
void CAVEExit(void)
.........................................................................................................................................................
void CAVEFrameFunction(CAVECALLBACK
.........................................................................................................................................................
function,int num_args,...)
void CAVEInit(void).........................................................................................................................................................
void CAVEInitApplication(CAVECALLBACK
.........................................................................................................................................................
function,int num_args,...)
void CAVEStopApplication(CAVECALLBACK
.........................................................................................................................................................
function,int numargs,...)
6.2.2 Miscellaneous..........................................................................................................................................................
CAVELib Functions
void CAVEAddCallback(CAVEID cbtype, CAVECALLBACK function,
void *app_data)
.........................................................................................................................................................
volatile void * CAVEAllocDisplayData(size_t
.........................................................................................................................................................
size)
volatile void * CAVEAllocDisplayDataByID(int
.........................................................................................................................................................
id,size_t size)
int CAVEButtonChange(int
.........................................................................................................................................................
button)
float CAVEConvertFromCAVEUnits(float
.........................................................................................................................................................
val,CAVEID units)
float CAVEConvertToCAVEUnits(float
.........................................................................................................................................................
val,CAVEID units)
© 2010 enter value here
54
54
55
55
55
55
55
56
56
56
56
57
57
57
III
CAVELib 3.2.1 User and Reference Guide
void CAVEDisplayBarrier(void)
.........................................................................................................................................................
boolean CAVEDisplayDataChanged(volatile
.........................................................................................................................................................
void *buf)
boolean CAVEDisplayDataChangedByID(int
.........................................................................................................................................................
id)
boolean CAVEDisplayDataIDExists(int
.........................................................................................................................................................
id)
void CAVEDisplaySync(void)
.........................................................................................................................................................
void CAVEDistribBarrier(int
.........................................................................................................................................................
chanID)
void CAVEDistribCloseConnection(int
.........................................................................................................................................................
chanID)
boolean CAVEDistribMaster(void)
.........................................................................................................................................................
int CAVEDistribNumNodes(void)
.........................................................................................................................................................
void CAVEDistribOpenConnection(int
.........................................................................................................................................................
chanID)
int CAVEDistribRead(int
.........................................................................................................................................................
chanID,void *buffer,size_t size)
void CAVEDistribWrite(int
.........................................................................................................................................................
chanID,void *buffer,size_t size)
void CAVEFree(void.........................................................................................................................................................
*mem)
void CAVEFreeLock(CAVELOCK
.........................................................................................................................................................
lock)
void CAVEGetActiveChannels(CAVEID
.........................................................................................................................................................
wall[CAVE_NUM_WALL_IDS])
boolean CAVEgetbutton(CAVE_DEVICE_ID
.........................................................................................................................................................
device)
volatile void * CAVEGetDisplayData(volatile
.........................................................................................................................................................
void *buf,size_t *size)
volatile void * CAVEGetDisplayDataByID(int
.........................................................................................................................................................
id,size_t *size)
int CAVEGetDisplayDataID(void
.........................................................................................................................................................
*buf)
void CAVEGetEyePosition(CAVEID
.........................................................................................................................................................
eye,float *x,float *y,float *z)
int CAVEGetFrameNumber(void)
.........................................................................................................................................................
void CAVEGetOrientation(CAVEID
.........................................................................................................................................................
oname,float *angle)
void CAVEGetPipeChannels(CAVEID
.........................................................................................................................................................
wall[CAVE_NUM_WALL_IDS])
void CAVEGetPosition(CAVEID
.........................................................................................................................................................
posname,float *pos)
void CAVEGetSensorOrientation(CAVE_SENSOR_ST *sensor,CAVEID
frame,float *angle) .........................................................................................................................................................
void CAVEGetSensorPosition(CAVE_SENSOR_ST *sensor,CAVEID
frame,float *pos)
.........................................................................................................................................................
void CAVEGetSensorVector(CAVE_SENSOR_ST *sensor,CAVEID
vecname,float *vec) .........................................................................................................................................................
float CAVEGetTime(void)
.........................................................................................................................................................
long CAVEgetvaluator(CAVE_DEVICE_ID
.........................................................................................................................................................
device)
void CAVEGetVector(CAVEID
.........................................................................................................................................................
vectorid,float vector[3])
void CAVEGetViewport(int
.........................................................................................................................................................
*origX,int *origY,int *width,int *height)
void CAVEGetWallCorners(CAVE_WALL_ID id, float* ll, float* ul, float*
lr)
.........................................................................................................................................................
void CAVEGetWallCornersEye(CAVE_WALL_ID id, CAVEID walleye,
float* ll, float* ul, float*
.........................................................................................................................................................
lr)
void CAVEGetWindowGeometry(int *origX,int *origY,int *width,int
*height)
.........................................................................................................................................................
GLXContext CAVEGLXContext(void)
.........................................................................................................................................................
void CAVEHalt(void)
.........................................................................................................................................................
void CAVEHeadTransform(void)
.........................................................................................................................................................
int CAVEInStereo(void)
.........................................................................................................................................................
void *CAVEMalloc(size_t
.........................................................................................................................................................
size)
boolean CAVEMasterDisplay(void)
.........................................................................................................................................................
boolean CAVEMasterWall(void)
.........................................................................................................................................................
void CAVENavConvertCAVEToWorld(float inposition[3],float
outposition[3])
.........................................................................................................................................................
void CAVENavConvertVectorCAVEToWorld(float invector[3],float
outvector[3])
.........................................................................................................................................................
void CAVENavConvertVectorWorldToCAVE(float invector[3],float
outvector[3])
.........................................................................................................................................................
void CAVENavConvertWorldToCAVE(float inposition[3],float
outposition[3])
.........................................................................................................................................................
57
57
57
58
58
58
58
58
58
58
59
59
59
59
59
59
60
60
60
60
60
60
61
61
61
61
61
62
62
62
62
62
63
63
63
63
63
63
64
64
64
64
64
64
64
© 2010 enter value here
Contents
IV
void CAVENavGetMatrix(Matrix
.........................................................................................................................................................
m)
void CAVENavInverseTransform()
.........................................................................................................................................................
void CAVENavLoadIdentity(void)
.........................................................................................................................................................
void CAVENavLoadMatrix(Matrix
.........................................................................................................................................................
m)
void CAVENavLock(void)
.........................................................................................................................................................
void CAVENavMultMatrix(Matrix
.........................................................................................................................................................
m)
void CAVENavPreMultMatrix(Matrix
.........................................................................................................................................................
m)
void CAVENavRot(float
.........................................................................................................................................................
angle, char axis)
void CAVENavScale(float
.........................................................................................................................................................
xscale, float yscale, float zscale)
void CAVENavTransform()
.........................................................................................................................................................
void CAVENavTranslate(float
.........................................................................................................................................................
xtrans, float ytrans, float ztrans)
void CAVENavUnlock(void)
.........................................................................................................................................................
void CAVENavWorldRot(float
.........................................................................................................................................................
angle, char axis)
void CAVENavWorldScale(float
.........................................................................................................................................................
xscale, float yscale, float zscale)
void CAVENavWorldTranslate(float
.........................................................................................................................................................
xtrans, float ytrans, float ztrans)
CAVE_USER_ST * CAVENetFindUser(CAVENETID
.........................................................................................................................................................
id)
void CAVENetGetOrientation(volatile CAVE_USER_ST *user,CAVEID
oname,float *or)
.........................................................................................................................................................
void CAVENetGetPosition(volatile CAVE_USER_ST *user,CAVEID
posname,float *pos) .........................................................................................................................................................
void CAVENetGetVector(volatile CAVE_USER_ST *user,CAVEID
vecname,float *vec) .........................................................................................................................................................
void CAVENetHeadTransform(volatile
.........................................................................................................................................................
CAVE_USER_ST *user)
int CAVENetReceive(void
.........................................................................................................................................................
*buf,size_t size,CAVE_USER_ST **user)
void CAVENetSend(void
.........................................................................................................................................................
*data,size_t size)
void CAVENetWandTransform(volatile
.........................................................................................................................................................
CAVE_USER_ST *user)
int CAVENewID(void)
.........................................................................................................................................................
CAVELOCK CAVENewLock(void)
.........................................................................................................................................................
int CAVENumPipes(void)
.........................................................................................................................................................
void CAVEPassAllDisplayData(void)
.........................................................................................................................................................
void CAVEPassDisplayData(volatile
.........................................................................................................................................................
void *buf,size_t size)
void CAVEPassDisplayDataByID(int
.........................................................................................................................................................
id,size_t size)
int CAVEPipeNumber(void)
.........................................................................................................................................................
CAVEID CAVEProcessType(void)
.........................................................................................................................................................
void CAVEResetTracker(void)
.........................................................................................................................................................
void CAVEScramnetFree(void
.........................................................................................................................................................
*mem)
void * CAVEScramnetMalloc(size_t
.........................................................................................................................................................
size)
void CAVESensorTransform(CAVE_SENSOR_ST
.........................................................................................................................................................
*sensor)
void CAVESetOption(CAVEID
.........................................................................................................................................................
option,int value)
CAVE_DIST_NETWORKSLAVE
.........................................................................................................................................
CAVE_GL_ACCUMSIZE .........................................................................................................................................
CAVE_GL_SAMPLES
.........................................................................................................................................
CAVE_GL_ACCUMSIZE .........................................................................................................................................
CAVE_GL_ALPHASIZE .........................................................................................................................................
CAVE_GL_SAMPLES
.........................................................................................................................................
CAVE_GL_STENCILSIZE .........................................................................................................................................
CAVE_NET_BUFFERSIZE.........................................................................................................................................
CAVE_NET_NUMBUFFERS
.........................................................................................................................................
CAVE_NET_UPDATELOCALDATA
.........................................................................................................................................
CAVE_PROJ_INCLUDENAVIGATION
.........................................................................................................................................
CAVE_PROJ_USEWINDOW
.........................................................................................................................................
CAVE_PROJ_USEMODELVIEW
.........................................................................................................................................
CAVE_SCRAMNET_ARENASIZE
.........................................................................................................................................
CAVE_SHMEM_SIZE
.........................................................................................................................................
© 2010 enter value here
65
65
65
65
65
65
66
66
66
66
66
66
66
66
67
67
67
67
67
68
68
68
68
68
68
69
69
69
69
69
69
69
70
70
70
70
70
71
71
71
71
71
71
71
72
72
72
72
72
72
73
V
CAVELib 3.2.1 User and Reference Guide
CAVE_SHMEM_ADDRESS
.........................................................................................................................................
CAVE_SIM_DRAWOUTLINE
.........................................................................................................................................
CAVE_SIM_DRAWTIMING
.........................................................................................................................................
CAVE_SIM_DRAWUSER .........................................................................................................................................
CAVE_SIM_DRAWWAND.........................................................................................................................................
CAVE_SIM_VIEWMODE .........................................................................................................................................
CAVE_TRACKER_SIGNALRESET
.........................................................................................................................................
void CAVESetReadLock(CAVELOCK
.........................................................................................................................................................
lock)
void CAVESetWriteLock(CAVELOCK
.........................................................................................................................................................
lock)
void CAVESleep(float
.........................................................................................................................................................
seconds)
CAVEID CAVEUnits(void)
.........................................................................................................................................................
void CAVEUnsetReadLock(CAVELOCK
.........................................................................................................................................................
lock)
void CAVEUnsetWriteLock(CAVELOCK
.........................................................................................................................................................
lock)
void *CAVEUserSharedMemory(int
.........................................................................................................................................................
size)
void CAVEUSleep(unsigned
.........................................................................................................................................................
long milliseconds)
CAVE_WALL_ID CAVEWallName(char*
.........................................................................................................................................................
wallName)
char * CAVEWallName(CAVE_WALL_ID
.........................................................................................................................................................
wall)
void CAVEWallTransform(void)
.........................................................................................................................................................
void CAVEWandTransform(void)
.........................................................................................................................................................
Display * CAVEXDisplay(void
.........................................................................................................................................................
XVisualInfo * CAVEXVisualInfo(void)
.........................................................................................................................................................
Window CAVEXWindow(void)
.........................................................................................................................................................
73
73
73
73
73
73
74
74
74
74
74
74
75
75
75
75
75
75
76
76
76
76
76
6.3 CAVE Macros...................................................................................................................................
and Variables
..........................................................................................................................................................
76
6.3.1 Sensor & Controller
Macros
CAVESENSOR(i) .........................................................................................................................................................
CAVENETSENSOR(user,i)
.........................................................................................................................................................
CAVEBUTTONn = [.........................................................................................................................................................
0|1]
CAVE_JOYSTICK_X.........................................................................................................................................................
CAVE_JOYSTICK_Y.........................................................................................................................................................
..........................................................................................................................................................
6.3.2 Global Variables
int CAVENear,CAVEFar
.........................................................................................................................................................
int CAVEEye
.........................................................................................................................................................
int CAVEWall
.........................................................................................................................................................
float *CAVEFramesPerSecond
.........................................................................................................................................................
float *CAVETime .........................................................................................................................................................
char *CAVEVersion .........................................................................................................................................................
CAVE_CONTROLLER_ST
.........................................................................................................................................................
*CAVEController
int *CAVENumUsers
.........................................................................................................................................................
CAVE_USER_ST **CAVEUser
.........................................................................................................................................................
76
77
77
77
77
77
77
78
78
78
78
78
78
78
79
79
6.4 Environment ...................................................................................................................................
Variables
6.4.1 CAVE_HOME.......................................................................................................................................................... 79
.......................................................................................................................................................... 79
6.4.2 CAVEDEBUGCONFIG
Chapter 7 - Supporting Software
79
Chapter 8 - CAVELib with FLEXlm Licensing
81
8.1 Introduction ...................................................................................................................................
...................................................................................................................................
8.2 Benefits
...................................................................................................................................
8.3 Installing
8.4 Terminology ...................................................................................................................................
81
81
81
84
© 2010 enter value here
Contents
VI
Chapter 9 - Bergen Sound Server & Library
85
9.1 Introduction ................................................................................................................................... 85
................................................................................................................................... 85
9.2 Library Interface
9.3
..........................................................................................................................................................
9.2.1 bergenServer class
9.2.2 bergenSound ..........................................................................................................................................................
class
9.2.3 bergenSample..........................................................................................................................................................
class
...................................................................................................................................
snerd
Chapter 10 - CAVELib 3.2.1 Install Guide
...................................................................................................................................
10.1 Step One - Hardware
...................................................................................................................................
10.2 Step Two - Installation
10.3 Step Three -...................................................................................................................................
Configuration Files
...................................................................................................................................
10.4 Step Four - Testing
Appendix A - CAVELib ChangeLog
© 2010 enter value here
85
86
87
87
88
88
88
89
92
93
1
CAVELib 3.2.1 User and Reference Guide
Chapter 1 - CAVELib Programming
1.1 Introduction
CAVELib™ is a powerful application programmer interface (API) that provides the cornerstone for
creating robust interactive three-dimensional (i3D) environments. Use of CAVELib dramatically
increases the ability to create visual solutions for a multitude of display technologies without
concerning the developer with the intricacies of programming for a multi-wall or cluster system.
CAVELib's API abstracts the difficulty of those details, enabling developers to build high-end i3D
applications to meet their unique challenges using Windows® or Linux™ operating systems, on either
enterprise systems or PC clusters.
i3D applications bring the capacity for engaging visual information from multiple perspectives, which
enhances understanding and increases the efficiency in gaining knowledge. CAVELib can be used to
develop i3D applications for a host of essential processes, including product development, research,
engineering, manufacturing, training, medicine, and marketing. CAVELib applications have been
written to allow users to view multiple design iterations without expensive design mock-ups, as well as
communicate virtually face-to-face with collaborators around the world.
With no effort on the developer's part, CAVELib calculates off-axis perspective transformation matrices
for the display device, synchronizes multiple display processes, and draws stereoscopic views.
Organizations choosing to use i3D display systems should employ CAVELib to achieve rapid
deployment to these systems.
ACKNOWLEDGEMENT: The CAVELib has had over a decade of development and use since the
CAVE's first debut at the 1992 ACM Siggraph convention in Chicago. The CAVELib was designed and
developed at the Electronic Visualization Laboratory under the direction of Tom DeFanti and Dan
Sandin, with principle programming work by Carolina Cruz-Neira, Marek Czernuszenko, and Dave
Pape. The development of the CAVELib has also been greatly affected and improved though its wide
spread uses in research and academic areas. These improvements came namely through the
valuable input of the talented staff and students at the National Center for Super Computing
Applications and Argonne National Labratories. Additional input has come from the participants in the
various international exhibitions of VR technology that were based on the CAVELib, including VROOM
at Siggraph94, and the I-Way at Supercomputing in 1995. Mechdyne humbly acknowledges the hard
work and brilliant thought of all of the people who have made the CAVELib the robust set of libraries
that it has become. You, as a user, are part of this continual advancement of i3D and the CAVELib,
and your input is an important contribution. We welcome your comments, opinions, advice and
suggestions, please send them to the [email protected].
1.2 Compiling a CAVELib Program
1.2.1 CAVELib Applications
A CAVELib program needs to include the appropriate CAVELib header file - cave_ogl.h for OpenGL
programs, and pfcave.h for Peformer programs.
OpenGL programs need to be linked with the OpenGL CAVELib, the OpenGL library, the math library,
the X libraries and the pthreads library (e.g. -lcave_ogl_mt -lGL -lX11 -lXi -lm
-lpthreads). Additionally,
© 2010 enter value here
Chapter 1 - CAVELib Programming
·
·
2
HPUX requires a -Aa switch, the -L/opt/graphics/OpenGL/lib directory, and the -lXext library.
SUN requires the -L/usr/openwin/lib directory, and the -lsocket and -lnsl libraries.
Please refer to the CAVE/examples/OpenGL/ directory for example Makefile and Windows project
files.
Performer is no longer supported. If Performer use is required, CAVELib 3.2.0 and earlier must be
used.
The CAVELib libraries are compiled for several platforms LINUX and WIN32. All platforms have 32 bit
libraries. All libraries reside in either CAVE/lib32/ or CAVE/lib64/, depending upon the bit architecture.
Furthermore, the OpenGL versions of the CAVELib come in both a multi-process version libcave_ogl.a
and a multi-threaded version libcave_ogl_mt.a. It is recommended that all new OpenGL CAVELib
users make use of the multi-threaded library,libcave_ogl_mt.a, as this is the programing paradigm that
is prevelent for multi-processor computing. Existing users should likely change from multi-process to
multi-threading. Migrating from multi-process to multi-threading is generally painless, since if the
application already had proper locks and memory sharing for multi-process it should be ready for
multi-threading. Furthermore, the special requirement of shared memory needed in multi-processing is
no longer required. So these mechanisms could be removed, although it is perfectly safe to still do
CAVEmalloc, in an MT application the CAVELib actually executes a standard malloc when
CAVEmalloc is called.
If the Bergen audio classes are being used, the Bergen libraries will need to be linked into the
CAVELib application as well. To learn how to use the Bergen audio library, see the documentation,
found in Part II, Auxiliary Software section of this manual.
You can also use the Vanilla Sound Server (vss) by the Audio Development Group at the National
Center for Supercomputing Applications, by downloading then including vssClient.h (after cave_ogl.h)
and linking with the vss library (-lsnd). Further information can be found through the NCSA web site,
http://www.isl.uiuc.edu/software/vss/
All CAVELib files are normally found in,
·
·
/usr/local/CAVE for LINUX
C:\Program Files\Mechdyne\CAVELib_3.2 for Windows
1.2.2 W2K CAVELib Application Projects
The example workspace and projects provide examples of the settings required to successfully build a
CAVELib application. The settings for these projects should be referred to and duplicated for your own
projects. The following sections will highlight the settings important for CAVELib development.
1.2.2.1
Workspace
A workspace will contain projects, and each project will contain the configuration settings and files for
creating an application. A workspace can contain multiple projects, but doesn't need to. Each project,
though, must belong to a workspace. Read the help pages in MSVC to learn more about Workspaces.
© 2010 enter value here
CAVELib 3.2.1 User and Reference Guide
3
1.2.2.2
Project
A project is a group of files and configurations that are used to create a new application or binary. A
new project can be created within MSVC using the "File->New" menu option, which will present a
dialog with "Projects" tab that lists a variety of options. All of the example applications are of type
"Win32 Console Application". This is the recommended project type and is the only supported project
type at this time. A Win32 console application has "main()" as the entry point to the program, as
opposed to other project types that have the Win32 specific "WinMain()" entry point.
If the developer is familiar with "WinMain()", then they may also choose the "Win32 Application" as a
project type, but should be aware that the CAVELib handles all Win32 events for windows it creates,
just as it does in X-Windows. MFC Applications are not officially supported at this time.
To create a new project (and with it a new application), select "File->New->Project". In the left pane of
the resulting dialog, expand "Visual C++", and select Win32. In the right pane, several project types will
appear. Select "Win32 Console Application". In the Name field enter a project name for the new
application, and also select a directory in which to create the project. When "OK" is selected a folder
containing the new project files will be created in the directory that was specified. If an existing solution
is open when creating a new project, a dropdown menu titled Solution will appear underneath the
Location field in the New Project dialog. By default, "Create new Solution" is selected. If the new
project should be contained within the open solution, change this option to "Add to Solution".
1.2.2.3
Project Settings
To access the settings for a project, select the menu item "Project->[Project Name] Properties…" or
right click the project in the Solution Explorer and select "Properties".
Most of the default settings created by MSVC for a "Win32 Console Application" can be used.
Listed below are the specific changes involved in for CAVELib applications. Note that for each project
you may make changes for "Debug", "Release", or "All Configurations". Except where noted, the
changes listed below should be done with "All Configurations" being selected in the pull-down menu of
"Configuration" which is in the upper left hand corner of the "Project Settings" dialog box.
In the left pane of the Properties dialog are two expandable options: "Configuration Properties" and
"Common Properties". Unless noted, all the sections listed below are underneath "Confguration
Properties".
C/C++ settings
Under the "C/C++" section are variety of settings that effect the compiling stage of the source code.
These settings are grouped into various categories.
General
Select the "General" section in the left pane and make the following changes:
Add to the "Additional include directories:" line the location of the CAVELib include directory, either as
a relative path from this project or as an absolute path. The relative path "..\..\include" works if the new
project is created in the same directory as the other example apps that are included in the CAVELib
installation. Otherwise you will need to adjust it accordingly. For portability it is recommended to use
relative paths. Code Generation
Select the "Code Generation" section in the left pane and be sure to use either of the following settings
for optimized or debug, static or run-time CAVELib to compile with:
· Under the "Runtime library" pull-down menu select "Multi-threaded DLL" or "Debug
© 2010 enter value here
Chapter 1 - CAVELib Programming
·
4
Multi-threaded DLL" if linking to the libcave_ogl_mt_MD.lib or libcave_ogl_mt_MDd.lib,
respectively.
Under the "Runtime library" pull-down menu select "Multi-threaded" or "Debug Multi-threaded" if
linking to the libcave_ogl_mt_MT.lib or libcave_ogl_mt_MTd.lib respectively.
PreprocessorSelect the "Preprocessor" section in the Property dialog's left pane and make the
following changes:
·
To the "Preprocessor definitions:" line add the following symbol: "STRICT" for strong type
checking is recommended.
Linker settings
Under the "Linker" section there are a variety of settings that affect the linking stage of the source
code. These settings are also grouped into various categories.
General
Select the "General" category and make the following change:
·
Add to the "Additional library directories:" text box the location of the CAVELib "lib\" directory.
This can be either a relative or absolute path. The relative path "..\..\lib32" works if the new
project is created in the same directory as the other example applications that are included in
the CAVELib installation. Otherwise you will need to adjust it accordingly.
Input
Select the category "Input" and make the following changes:
·
·
In the "Additional Dependencies" text box add "opengl32.lib glu32.lib wsock32.lib" separated
by spaces.
Also add to this line the appropriate name of the version of the CAVELib you are linking to,
which is determined by the Code Generation settings described in the above section, ie,
"libcave_ogl_mt_MD.lib" if you selected "Multi-thread DLL" for the C run-time.
NOTE – When linking with the versions of the CAVELib that were compiled using the debug versions
of the C run-time, libcave_ogl_mt_MDd.lib or libcave_ogl_mt_MTd.lib, the linker may report the
following warning:
LINK : warning LNK4098: defaultlib "MSVCRT" conflicts with use of other libs; use
/NODEFAULTLIB:library
This may be a result of the fact that, while the CAVELib library itself is compiled to use the Debug C
run-time lib, the CAVELib includes code from FLEXlm for licensing. The FLEXlm libraries were
compiled with the release versions of the C run-time lib. In this case, the warning should be harmless
because FLEXlm and CAVELib do not exchange any heap allocated memory, which is typically where
errors occur since the Release version of the C libraries allocate memory differently than the Debug C
libraries.
1.2.2.4
Source Files
Before an application can be built a source file needs to be added to the project. This can be done by
selecting "Project->Add New Item". In the "Add New Item" dialog box, select either "Header File (.h)" or
© 2010 enter value here
5
CAVELib 3.2.1 User and Reference Guide
"C++ File (.cpp)" from the right hand pane.
1.3 CAVELib Callbacks
There are three types of callbacks in the CAVELib; display, frame update, and initialization.
The graphics routine is passed to the CAVELib as a display callback function. The user's graphics
routine is then called by the CAVELib's display loop for each view to be rendered. This approach
allows the CAVELib to take care of all necessary projections and synchronization for the user,
regardless of the VR device that is being used.
The rendering for each graphics window going to a VR device is done in a separate thread (see
Multithreading below). When a stereo display is used, each display thread will call the application's
display function twice per frame when in stereo, in mono-scopic mode it is called once per frame. The
general rule is there are as many threads as there are pipes, and that for each thread the draw
function is called once per frame - per eye - per channel - for a pipe. (For clarification a pipe can be
thought of as a graphics card. Each video output from that graphics card/pipe is a channel.)
Because the application does not know in advance how often the display function will be called in each
thread, a "frame function" callback is provided. This callback will always be called exactly once per
frame in each rendering thread, prior to the display callback being called. This gives a user the ability
to perform calculations once per frame in each thread.
The initialization callback will be called exactly once, at the beginning of the next frame after it is
defined, or in the first frame if it is called prior to CAVEInit(). 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 passed to CAVEFrameFunction(). The initialization callback is passed to
CAVEInitApplication().
1.4 Rendering
The user's program should not attempt to perform any windowing operations or make any perspective
projection calculations. The CAVELib does that work, and and will do so correctly for whatever VR
display device it is configured for.
A CAVELib application is by default set to render in RGBA mode, double-buffered, with z-buffering.
Users should not issue the swapbuffers command; it is handled internally by the CAVELib. The
developer is responsible for any other graphics commands, such as lighting, object transformations,
smoothing of lines, and clearing the screen, there are no default actions for these functions.
The CAVELib can use one of two API's for rendering OpenGL or OpenGL Performer. Scene graphs
that are based on OpenGL may also be used as the rendering engine with the CAVELib. VTK,
OpenRM, Open Inventor and Volumizer have all been used by customers with the OpenGL CAVELib.
When using the CAVELib on a visualization cluster the CAVELib handles the frame and buffer swap
synchronization between the PCs. The user need not worry if the draw function on each PC will be
using the same tracker or input data for a frame, the CAVELib guarantees data synchronization of its
internal variables for the user.
© 2010 enter value here
Chapter 1 - CAVELib Programming
6
1.5 Interaction
A user interacts with a CAVELib application using a tracker and an input controller (wand, gloves, etc.)
when in an immersive display device, but uses the keyboard and mouse on a desktop. Trackers report
the position and orientation of its sensors; and input controllers usually consist of a set of buttons and
valuators, such as a joystick, that reports floating point values (usually normalized to a range between
-1 and 1). The CAVELib does not talk directly to trackers and input devices. Instead a middleware
application called trackd reads data from devices and puts the information into system shared
memory. From system shared memory other applications, such as a CAVELib application, can read
the data at will.
The tracker's and controller's data structures are updated from the trackd's shared memory once per
display frame. Thus, the values will remain constant during a given frame, and for each thread. Several
CAVELib library functions are available to then access this data within the application as well as to
obtain derived values, such as the front vector of a tracker sensor. When using the CAVELib in a
cluster, the CAVELib guarantees that the trackd data will be the same for each frame on each
machine.
1.5.1 Trackers
In the past, the library supported exactly two tracker sensors - one for the user's head, and one for the
wand - and much of the API reflects this legacy, although the current CAVELib supports up to 32
sensors. The sensor data is accessible through a global structure pointed to by CAVEptr; the number
of sensors being read is obtained from CAVEptr->num_sensors, and the array
CAVEptr->sensor[] contains pointers to the data for each sensor. CAVESENSOR(i) is a macro
that returns a pointer to the i'th sensor. The first sensor, CAVEptr->sensor[0] is always the sensor
used for the user's head position and orientation and in calculating the view perspective and matrices.
The remaining sensors are the controller 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() functions return values
for either the head or the wand, based on the id argument. CAVEGetSensorPosition(),
CAVEGetSensorOrientation(), and CAVEGetSensorVector() functions 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, or in the application's world coordinate system, as defined by the
navigation matrix. For further information see the chapter "Functions, Data Types & Macros".
© 2010 enter value here
7
CAVELib 3.2.1 User and Reference Guide
1.5.2 Controller
The values of the buttons and/or valuators on the WAND (or other control device) are stored in the
global structure pointed to by CAVEController. The typical 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: the macro numbering of the buttons start from
1, rather than 0, so CAVEBUTTON1 corresponds to CAVEController->button[0], etc.)
The values in CAVEController structure reflect the current state of the buttons and valuators; the
function CAVEButtonChange() is an additional feature that 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 used by the CAVEBUTTON macros. For further information see the chapter
"Functions, Data Types & Macros".
1.6 Navigation
Most VR display structures and their 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 that simulates moving the VR device's physical coordinate
system around in the virtual world. The CAVELib maintains a navigation transformation matrix that 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 to a lesser use
CAVENavScale(). The transformations are all defined relative to the physical coordinate system; i.e.
a CAVENavTranslate(0.0,0.0,-1.0) will move the user's device coordinate space (local
coordinates) through the virtual world one unit along the worlds -Z axis, and a
CAVENavRot(30.0,'y') will turn the user's view of the environment 30 degrees to the left. Other
functions for affecting the navigation matrix are CAVENavLoadIdentity(),
CAVENavLoadMatrix(), CAVENavMultMatrix(), and CAVENavGetMatrix().
When the CAVELib executes an application's display function, the default coordinate system is still the
physical coordinates. To render objects properly in a navigated environment the application should
call CAVENavTransform() prior to any graphics calls.
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. One suggestion is to calculate navigation amounts and make the navigation function calls
once per frame in the master process so that all display processes have the same value prior to
rendering any graphics.
© 2010 enter value here
Chapter 1 - CAVELib Programming
8
1.7 Multi-Threading
The CAVELib splits an application up into several pieces to handle the different tasks involved in
displaying a virtual environment, such as different viewports or windows. These pieces may either be
separate proceses or separate threads, depending on which CAVELib library an application is linked
to. Prior to version 3.1 of the CAVELib threads were not supported, instead the CAVELib only
supported a multi-processing paradigm. Multi-processing is inherently more difficult than
multi-threading, because of the need for a data passing mechanism to share variables and other data
between each process. The mechanism for doing this within the CAVELib is discussed further below.
(This document does not go into detail regarding the differences between multi-processing and
multi-threading. That is best left to a college-level operating systems course text book.)
Regardless if multi-processing or multi-threading is being used each thread/process is created by
CAVEInit(). Only the parent application process will return from CAVEInit(); the child
threads/processes start infinite loops that perform the execution of internal library functions and user
callbacks. The CAVELib creates one display thread/process per graphics pipe, one thread/process for
tracking (if tracking is not enabled to be serial), one thread/process for networking (if networking is
enabled), and the main parent process. Even in multi-threading there is still a process, it is the
parent/main process, and all threads are spawned from it.
To maintain the highest possible frame rates, the display threads/processes should be implemented to
only perform rendering actions. All computations should be done in the main (aka parent) application
process if possible. Which leads to the requirement of getting data from the main process to each
display thread/process. Furthermore these display threads/processes are running in parallel. Because
of this parallel approach, it may be necessary to guarantee that the main process does not modify
shared data while the display threads/processes are using it. The best method to eliminate data
corruption is by making the data access mutually exclusive between threads/processes. One such way
is to use locks or semaphores to limit simultaneous access to shared data. The CAVELib includes
several routines for user convenience (CAVENewLock(), CAVEFreeLock(), CAVESetReadLock(),
CAVEUnsetReadLock(), CAVESetWriteLock(), CAVEUnsetWriteLock()) which provide
two-level access control. If the display threads/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 thread/process (like the main process) to change the data at a time.
1.7.1 Shared Memory
The CAVELib used to only support multi-processing, in this paradigm each display pipe was an
independent process with its own memory addresses. Because of this, if the main application process
were to do any calculations the application developer would need to have a mechanism to pass the
data to each of the display processes. For example, if the height of a bouncing ball was calculated in
the main process, each display process would need to obtain the value of the new height of the ball
each frame. One mechanism of passing this data into the display process is by shared memory.
Shared memory is specially allocated memory that allows multiple proceesses to have read and write
permissions to the same address. So within a multi-processing application the main process and the
display processes could use shared memory for any common data that had to be exchanged between
them. The CAVELib API functions CAVEMalloc() and CAVEFree() can be used to allocate and
release shared memory, in the same manner as malloc() and free()can be used to allocate and
release regular memory. The amount of shared memory that can be allocated depends on the size of
the application's shared memory arena, which can be set using CAVESetOption() this must be done
before calling CAVEConfigure() though, as it is withing this function that the arena is created.
Alternatively, CAVEUserSharedMemory() can be called to create a shared memory arena, which can
then be used with amalloc() (part of IRIX'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 must be
© 2010 enter value here
9
CAVELib 3.2.1 User and Reference Guide
allocated before CAVEInit() is called. Shared memory allocated from the arena after calling
CAVEInit() is visible to all processes, but a pointer will need to be passed to any processes other
than the process making the allocation. When using multi-threading instead of multi-processing these
extra steps for sharing data are no longer needed. That's because threads share a common memory
address space, in a sense all dynamic memory is shared by default when using threads.
1.7.2 Data Synchronization
As noted above, the library will fork a separate thread/process for each graphics pipe. This means that
the application's display function may be called several times in parallel; the exact number of
threads/processes varies depending on the configuration. But in some cases, an application developer
may want to have the display function perform an action or calculation that should only be done by one
process (such as diagnostic output or play an audio file). Because of this, the function
CAVEMasterDisplay() returns true in exactly one display thread/process. A developer can use this
function as a test to only enter a certain program section if indeed it is the master thread/process that
has made the function call.
Because only a single thread/process may be doing this calculation, even if it is small, it may cause
that thread/process to be slightly slower than the others. An undersirable effect would be if the master
thread/process was updating a data variable that all display threads/processes needed to use. But
since it takes some time to do the update, the non-master threads/processes may enter their rendering
portion and use the data prior to it being updated for that frame. So sometimes it becomes necessary
for an application developer to synchronize the display threads/processes if any data calculations are
being done outside of the main process. The function CAVEDisplayBarrier() was created to
cause the display threads/processes to block until all of them have called it. When using
CAVEDisplayBarrier(), a developer needs to be sure that all the display processes call it, else the
application will go into deadlock.
1.7.3 Program Flow
The following diagram shows how a CAVELib application operates "behind the scenes" using functions
and data that a developer supplies. The following example shows the multiple display threads for a
three pipe display system. Where each pipe may be either a graphics card in a larger enterprise
system, or the graphics card in a PC for a PC cluster.
© 2010 enter value here
Chapter 1 - CAVELib Programming
10
1.8 CAVELib On Clusters
Visualization systems for driving immersive 3D (i3D) displays can be characterized as a combination of
three hardware components. The first is computational power, which includes the CPU and main
memory, and for simplicity here, storage systems. The second is graphics power, which at the core is
the GPU (Graphics Processing Unit). The GPU is often referred to as a ‘graphic pipe’ or simply ‘pipe’,
and can output to 1 or more ‘video channels’ or simply ‘channels’. The third component is
communications, which is the glue that holds the first two components together. It includes things such
as networking, busses, etc.
Currently, many enterprise systems are capable of having multiple CPU's and GPU's as well as an
internal architecture that interconnects them with high-speed buses. These systems easily support
© 2010 enter value here
11
CAVELib 3.2.1 User and Reference Guide
multi-screened systems and are very commonly used as the image generator for i3D displays. But,
there is a growing trend to use commodity off-the-shelf hardware and PC workstations to drive
multi-wall visualization display systems. The difficulty with using workstations is that they generally are
single GPU systems. In order to display to a multi-wall system a cluster of these PC's need to be
interconnected and have software that allows multiple synchronized images to occur. In response to
this need the CAVELib has been enhanced to have the capabilities to support PC cluster setups.
For a cluster setup, the CAVELib has the responsibility for handling all internal data and frame
synchronizations between the multiple PCs, and does so without the developer having to do anything
to take advantage of it. In a cluster setup, the CAVELib works by having each PC running an exact
copy of the application. Because of this, the CAVELib only needs to pass minimal state information
each frame as well as have a barrier/acknowledgement mechanism for synchronization of each PC.
Because only minimal data needs to be passed each frame, the CAVELib in a cluster setup does not
have any unique networking requirements.
The one hardware requirement that any active stereo cluster visualization application will require is
video genlocking. Genlocking is the mechanism of having independent graphics cards all raster, or
display a particular frame buffer at the same time. The video signal that comes out of each graphics
card is controlled by the card and not the CAVELib software. Since many interactive 3D displays use
active stereo, the sequentially rendering of a left eye frame followed by a right eye frame, each of the
graphics cards need to be displaying its left eye image at the same time as the other cards. The same
is true for the right eye image. If the cards were not in sync, then when the shutter glasses had their
left eye open the user may not see the left eye image on all of the screens, the images would be out of
sync. Genlocking is a mechanism for making sure that the same image buffer is displayed from each
card at the same time. This mechanism is usually solved by a hardware mechanism on the graphics
cards themselves, as such, not all graphics cards have this capability.
To use a CAVELib-based application in a cluster setup, there is typically one PC per display screen.
One of these PCs should be considered the master. Since the PC’s are all running the same
application, they should also have the same system capabilities. The system will only run as fast as the
slowest PC in the cluster. Sometimes the master node will be more powerful than the slave nodes
because it does extra work that is shared to the other PC’s. If the setup is a four wall CAVE, for
example, then there should be four duplicate PCs with the CAVELib application running on each, with
a CAVELib configuration file that describes which wall that PC is responsible for. Occasionally, an
extra PC is used for attaching input devices to, such as trackers and controllers. The data would then
be shipped from that extra PC using the trackdserver to the master PC in the CAVELib cluster. The
master PC in the cluster must also be the one that is running trackd if input devices are being used.
To run the CAVELib in a cluster setup, there needs to be one PC per display screen. One of these
PCs should be called the master, and it does not matter which one is configured as the master. The
CAVELib does not require an extra non-graphical PC to be the master node. If the setup is a four wall
CAVE, then there should be four PCs with the CAVELib application running and each with a CAVELib
configuration file that describes which wall that PC is responsible for. Occasionally, an extra PC is
used for attaching input devices to, such as trackers and controllers. The data would then be shipped
from that extra PC using the trackdserver to the master PC in the CAVELib cluster. The master PC in
the cluster must also be the one that is running trackd if input devices are being used.
To run a cluster CAVELib application, the configuration file must be changed to denote that
applications should attempt to run in cluster mode. The main CAVELib option is Distribution and it
must be set to TCP to denote that this is a PC running in cluster mode. If the developer uses any of the
CAVELib cluster API calls for sharing application data then another option, AppDistribution, must
also be set to TCP in the configuration file. The total number of PCs in the cluster that are displaying to
a wall or a screen must be specified with the DistribNodes option. The hostname or IP address of
the PC that is considered to be the master node needs to be specified with the option
DistribTCPMaster. Also, the IP port the CAVELib should use to transfer data between the master
and the slaves must be set with DistribTCPPort option. The machine that is the master node is
specified as the master by having its DistribID set to 0 in its configuration file; the other machines
© 2010 enter value here
Chapter 1 - CAVELib Programming
12
(slaves) must each have a unique value for the DistribID from 1 to N-1, where N is the number of
PCs in the cluster.
The master node must also be the system that is running trackd if tracker or input devices are being
used. When distribution is enabled, the tracker data, controller data (including keyboard and mouse),
navigation matrix, and CAVELib's frame time are shared between the distributed machines. The
master node sends the latest values to the slave nodes at the beginning of each frame, and receives
an acknowledgement that each slave PC received the data before any PC is allowed to render the next
frame. All of this happens without any effort by the developer. In fact, many CAVELib applications that
run multi-wall on enterprise systems may run without modification on a PC cluster simply by
recompiling for that platform, and running with a proper CAVELib configuration file.
If an application is doing large computations or reading data from a remote resource (disk,
computational cluster, grid application, etc.) then the master node only should be responsible for this
data as well as sharing it to the slave nodes. A developer would program the application so that only
the master node is responsible for calculating or retrieving this new data and then have it share the
data to each of the slave nodes. This could be done using standard networking libraries (RPC, PVM,
etc.) or the CAVELib API for sharing data in a cluster may be used. To use the CAVELib functions for
distributing application data, the AppDistribution configuration option must be set to TCP.
If an application is doing large computations or reading data from a remote resource (disk,
computational cluster, grid application, etc.) then it's unlikely that a developer will want each node in
the PC cluster to be doing this activity. That would be redundant. Instead, what a developer should do
is program the application so that only the master node is responsible for obtaining or retrieving this
new data and then have it share the data to each of the slave nodes. This could be done using
standard networking libraries (RPC, PVM, etc.) or the API for data sharing that's part of the CAVELib
may be used. To use the CAVELib functions for distributing application data, the AppDistribution
configuration option must be set to TCP.
The CAVELib provides two mechanisms for sharing data, one is synchronized and one is not. The
synchronized (aka syncdata) method forces each call to block until all of the data is received by itself
and all of the other nodes. With larger amounts of data it is recommended that the syncdata API be
used in the application's main process, as opposed to the display thread, because it is decoupled from
the display thread, i.e. it runs independent of the frame rate. By passing the data into the main process
it is the users responsibility to determine how and when the data should then be used by each of the
display threads.
The other mechanism for passing data within a cluster of PCs uses a double buffering technique and
does not require any of the nodes to block, this is called the display data (aka dispdata) method. In this
mode, each node has two buffers, the write buffer that data is transferred in to by a separate thread,
and the read buffer that the application gets the data from. When data is done being transferred from
the master node into a slave's write buffer, the data is then swapped to the read buffer, and each call
to the read function will access this same data until new data is swapped into it. There is no guarantee
that all of the nodes will have the same values for their read buffer each frame, or that each node will
perform the buffer swap at the same time. Unlike the syncdata mechanism dispdata does not use
blocking to guarantee each node will have the exact same data each frame. Because of this, there is a
possibility that different nodes will have slightly different data each frame. For data that changes by
small amounts each frame, this lack of synchronization may be acceptable. The user needs to decide
if overall application frame rate or data synchronization is the most important and then use the
appropriate functions in the best way for their application.
The functions CAVEDistribOpenConnection(), CAVEDistribCloseConnection(),
CAVEDistribWrite() and CAVEDistribRead() are the functions that pass data by the syncdata
method. The functions CAVEAllocDisplayData(), CAVEPassDisplayData(), and
CAVEGetDisplayData() are the functions pass data by the dispdata method.
© 2010 enter value here
13
CAVELib 3.2.1 User and Reference Guide
Additionally, CAVEDistribMaster() returns true if its node is the master node, it can be used to
have only the master node perform certain computations. CAVEDistribBarrier() can be used to
synchronize processes on the multiple nodes. If Distribution isn't enabled, hence the application is
not running in a cluster, these functions will all return immediately without doing anything and
CAVEDistribMaster() will return true no matter which node it is executed on. Assuming
AppDistribution is set in the configuration file CAVEDistribOpenConnection() must be called
before CAVEDistribWrite(), CAVEDistribRead(), or CAVEDistribBarrier() are called; all
of these functions should only be called from same thread/process that called
CAVEDistribOpenConnection() for the connection channel they use (an application can open
multiple data passing channels, in different threads/processes). CAVEDistribCloseConnection()
should be called when the application exits, to close the communications channel and guarantee no
system resources are left around.
1.9 Form of a Basic CAVELib Program
1.9.1 Program Source Code
#include <cave_ogl.h>
#include <GL/glu.h>
void init_gl(void);
void draw(void);
GLUquadricObj *sphereObj;
int main(int argc,char **argv)
{
/* Initialize the CAVE */
CAVEConfigure(&argc,argv,NULL);
/* Give the library a pointer to the GL initialization function */
CAVEInitApplication(init_gl,0);
/* Give the library a pointer to the drawing function */
CAVEDisplay(draw,0);
/* Create the multiple processes/threads and start the display loop
*/
CAVEInit();
/* Wait for the escape key to be hit */
while (!CAVEgetbutton(CAVE_ESCKEY))
{
/* Nap so that this busy loop doesn't waste CPU time reset
timeval
struct every time for linux compatibility
*/
CAVEUSleep(10);
}
/* Clean up & exit */
© 2010 enter value here
Chapter 1 - CAVELib Programming
14
CAVEExit();
return 0;
}
/* init_gl - GL initialization function. This function will be called
exactly once by each of the drawing processes, at the beginning of
the next frame after the pointer to it is passed to CAVEInitApplication.
It defines and binds the light and material data for the rendering,
and creates a quadric object to use when drawing the sphere.
*/
void init_gl(void)
{
float redMaterial[] = { 1, 0, 0, 1 };
/* Enable light source 0 */
glEnable(GL_LIGHT0);
/* Set material to color both front and back face to a diffuse red */
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, redMaterial);
/* Create a glu quadric object */
sphereObj = gluNewQuadric();
}
/* draw - the display function. This function is called by the
CAVE library in the rendering processes' display loop. It draws a
sphere 1 foot in radius, 4 feet off the floor, and 1 foot in front
of the front wall (assuming a 10' CAVE).
*/
void draw(void)
{
/* Set clear color to black and clear both the screen and the zbuffer
*/
glClearColor(0., 0., 0., 0.);
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
/* Turn lighting on */
glEnable(GL_LIGHTING);
/* Draw a sphere */
glPushMatrix();
glTranslatef(0.0, 4.0, -4.0);
/* Draw a sphere using GLU quadric object.
Radius = 1
Slices = 8
Stacks = 8
*/
gluSphere(sphereObj, 1.0, 8, 8);
glPopMatrix();
© 2010 enter value here
CAVELib 3.2.1 User and Reference Guide
15
/* Turn lighting off */
glDisable(GL_LIGHTING);
}
1.9.2 Program Structure
CAVEConfigure(): This routine reads the CAVE configuration file, and parses the argc and argv
variables for any user-specified configuration options. After this function is called the application is
aware of how it is to run, number of walls and pipes, if it's stereo or mono, whether it will use trackd
input or keyboard and mouse, etc.
CAVEInit(): This routine initializes the CAVELib application. The primary operation that it performs is to
create the necessary display threads and data input thread that the CAVELib manages for the user.
When this function returns it is in the parent process, aka "computation process", and it executes the
rest of the code in main(). The new threads handle reading any input data and the rendering. There
is one rendering thread for each pipe. These threads call the application's init application callback
function once (whenever one is given), and each frame execute the the application's draw callback
function.
CAVEInitApplication(): Takes a pointer to the application's graphics initialization function and passes it
to each of the rendering threads. Since the rendering is not done by the computation process but
instead by a separate rendering process, the initialization of graphical objects that need to be local to a
thread must be done in each of the rendering threads, not in the parent process. The
CAVEInitApplication() function sets a pointer to the intialization function that's passed to it. This tells
the rendering thread what function to call, in this example init_gl(). Unless the CAVEInitApplication is
called multiple times, the function that is passed to it is called once and only once, it should be called
prior to CAVEDisplay, so that any constructs that are needed by draw exist, prior to its execution.
CAVEDisplay(): Takes a pointer to the application's drawing function which gets passed to each
rendering thread. Each rendering thread calls this function one or more times depending upon how
many viewports the thread is rendering for and how many eyes (mono, or stereo). Each thread is
responsible for setting up the proper view matrix before executing the draw function, so the application
should not call any functions that may affect the perspective matrix.
CAVEUsleep(): This forces the process to sleep for some number of micro seconds. The calling
process also relinquishes control of the processor allowing the OS to schedule another thread to run. If
this function is not called, the empty while loop could become a 'cpu hog' and slow down the
application's frame rate.
CAVEExit(): This causes all CAVE threads to shutdown, clean-up, and exit, and restores the machine
to its normal state.
Note: It is not required that CAVEInitApplication() be called if it is not needed. When it is used,
it should be called after CAVEInit() but before CAVEDisplay(). Also, if CAVEConfigure() is not
called, CAVEInit() will call it, this is not recommended as then any CAVELib configuration options
passed in via argc and argv variables will not be processed.
© 2010 enter value here
Chapter 2 - Simulation
16
Chapter 2 - Simulation
2.1 Introduction
The CAVELib provides options to simulate some or all of the hardware-specific parts of the CAVE-type
or Desk-type environment. This allows application developers to write and test code on ordinary
workstations, without requiring constant use of the virtual reality display device. There are three basic
areas that are simulated - the tracker input, the wand input, and the immersive visualization. When
running a CAVELib program, the configuration file 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). In simulator mode tracking and wand input are done via the keyboard and mouse; the
simulated display provides a user-perspective view, which is configurable with the configuration
variable "SimulatorView". Also an outside-the-CAVE third-person view is available.
2.2 Simulated Tracking
Simulated tracking is selected by the configuration option "TrackerType Simulator". The controls for
moving the simulated head and wand are given below.
2.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. To move the head in the desired
direction, use the corresponding commands below:
Move left
LEFT_ARROW
Move right
RIGHT_ARROW
Move forward
UP_ARROW
Move backward
DOWN_ARROW
Move up
SHIFT + UP_ARROW
Move down
SHIFT + DOWN_ARROW
Rotate left
ALT + LEFT_ARROW
Rotate right
ALT + RIGHT_ARROW
Rotate up
ALT + UP_ARROW
Rotate down
ALT + DOWN_ARROW
© 2010 enter value here
17
CAVELib 3.2.1 User and Reference Guide
Reset head and wand to initial positions P
2.2.2 Wand Controls
The wand is controlled using the mouse. Moving the mouse while holding down an appropriate key will
move or rotate the wand. As with the head, the wand is restricted to stay inside the CAVE's physical
boundaries. 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:
Move wand left/right/forward/back
Move wand left/right/up/down
CTRL + mouse movement
SHIFT + mouse movement
Rotate wand left/right/up/down ALT + mouse movement
Roll wand (rotate about Z)
<&>
Select wand 1/2/3/ as the current wand being controlled F1/F2/F3/
Reset wand to be in front of user
HOME
2.3 Simulated Wand Controls
The simulated wand controls (buttons & joystick) are selected by the configuration option "Wand
Simulator". Pressing the mouse buttons corresponds to pressing the wand buttons. Holding down the
spacebar while moving the mouse controls the joystick values. Note that the joystick controls set the X
and Y values based on the current position of the mouse in the application window, 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.
2.4 Simulated Display
The simulated display is selected by using the "simulator" wall (or "simulator1" or "simulator2") in the
Walls configuration option. There are three display modes for the simulator wall. In mode 0, it displays
what would be rendered on one of the CAVE walls; in mode 1, it displays a normal perspective view of
the application's environment from the position of the user's head; and in mode 2, it displays a
third-person view showing the user inside the CAVE. The simulator views can also show the position of
the user's head and of the wand, the current frame rate, and the outline of the physical CAVE, and can
black-out the parts of the scene which would not be visible due the lack of right, back, and ceiling
walls. The keyboard controls for these options are:
Switch to "CAVE mode" (for outline & blackout) C
© 2010 enter value here
Chapter 2 - Simulation
Switch to outside the CAVE mode, a.k.a. 3rd person
Switch to "Desk mode" (for outline & blackout)
D
Switch to user centered perspective mode
1
Switch to "wall-view" mode
2
0
Toggle blackout of right, rear, and ceiling walls
DEL
Toggle display of CAVE/Immersadesk outline
INSERT
Toggle display of user (head)
U
Toggle display of wand W
Toggle timing (frame rate) display
Print help text
T
H
When in wall-view mode (mode 0), the following keys select which wall's display is rendered:
Front wall
F
Left wall
L
Right wall
R
Floor ("bottom")
B
ImmersaDesk (screen7)
D
When using the outside-the-CAVE view, you can move the viewpoint around with the following
controls:
Rotate the viewpoint
Zoom in/out
KEYPAD -/+
Reset the viewpoint
© 2010 enter value here
KEYPAD ARROWS (2,4,6,8)
KEYPAD 5
18
CAVELib 3.2.1 User and Reference Guide
19
Chapter 3 - Sample Programs
3.1 CAVELib Sample Program 1
This application draws a red sphere at (0,4,-4).
#include <cave_ogl.h>
#include <GL/glu.h>
void init_gl(void);
void draw(void);
GLUquadricObj *sphereObj;
int
main(int argc,char **argv) {
/* Initialize the CAVE */
CAVEConfigure(&argc,argv,NULL);
/* Give the library a pointer to the GL initialization function */
CAVEInitApplication(init_gl,0);
/* Give the library a pointer to the drawing function */
CAVEDisplay(draw,0);
/* Create the multiple processes/threads and
start the display loop */
CAVEInit();
/* Wait for the escape key to be hit */
while (!CAVEgetbutton(CAVE_ESCKEY)) {
/* Nap so that this busy loop doesn't waste CPU time
reset timeval struct every time for linux compatibility
*/
CAVEUSleep(10);
}
/* Clean up & exit */
CAVEExit();
return 0;
}
/* init_gl - GL initialization function. This function will be called
exactly once by each of the drawing processes, at the beginning of
the next frame after the pointer to it is passed to CAVEInitApplication.
It defines and binds the light and material data for the rendering,
© 2010 enter value here
Chapter 3 - Sample Programs
20
and creates a quadric object to use when drawing the sphere.
*/
void init_gl(void) {
float redMaterial[] = { 1, 0, 0, 1 };
/* Enable light source 0 */
glEnable(GL_LIGHT0);
/* Set material to color both front and back face to a diffuse red */
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, redMaterial);
/* Create a glu quadric object */
sphereObj = gluNewQuadric();
}
/* draw - the display function. This function is called by the
CAVE library in the rendering processes' display loop. It draws a
sphere 1 foot in radius, 4 feet off the floor, and 1 foot in front
of the front wall (assuming a 10' CAVE).
*/
void draw(void) {
/* Set clear color to black and clear both the screen and the zbuffer
*/
glClearColor(0., 0., 0., 0.);
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
/* Turn lighting on */
glEnable(GL_LIGHTING);
/* Draw a sphere */
glPushMatrix();
glTranslatef(0.0, 4.0, -4.0);
/* Draw a sphere using GLU quadric object.
Radius = 1
Slices = 8
Stacks = 8
*/
gluSphere(sphereObj, 1.0, 8, 8);
glPopMatrix();
/* Turn lighting off */
glDisable(GL_LIGHTING);
}
3.2 CAVELib Sample Program 2
This example draws a yellow grid pattern on the floor. It has red and blue bouncing spheres, and the
user is able to navigate about the environment simply by pointing in the direction they wish to go and
pressing the wand's joystick.
© 2010 enter value here
21
CAVELib 3.2.1 User and Reference Guide
/* navigate1_mt.c
An example of navigating in a CAVE environment. The world is that
of bounce.c. The user navigates using the wand joystick - JOYSTICK_Y
controls the forward/back motion; JOYSTICK_X controls turning.
*/
#include <cave_ogl.h>
#include <GL/glu.h>
#ifndef WIN32
#include <strings.h>
#endif
#define SPEED 5.0f /* Max navigation speed in feet per second */
/* Values used for drawing a grid for the ground */
#define N 50
#define INCGRID 5
/* The data that will be shared between processes */
typedef struct spheredata {
float y;
}SPHEREDATA;
/* Global pointer to shared memory */
SPHEREDATA* sphere;
#ifndef CAVE_THREAD
static GLuint redMat, blueMat;
static GLUquadricObj *sphereObj;
#else
static GLuint redMat[CAVE_MAX_WALLS], blueMat[CAVE_MAX_WALLS];
static GLUquadricObj *sphereObj[CAVE_MAX_WALLS];
#endif
/* function prototypes */
void initGL(void);
void drawSpheres(void);
void drawGround(void);
void initSphereMem(void);
void frameUpdate(void);
void compute(void);
void navigate(void);void
int main(int argc,char **argv) {
CAVEConfigure(&argc,argv,NULL);
/* Initialize sphere memory */
initSphereMem();
CAVEInitApplication(initGL,0);
/* Give the library a pointer to the drawing function */
CAVEDisplay((CAVECALLBACK)drawSpheres,0);
/* Give the library a pointer to an update function */
CAVEFrameFunction((CAVECALLBACK)frameUpdate,0);
© 2010 enter value here
Chapter 3 - Sample Programs
22
CAVEInit();
while (!CAVEgetbutton(CAVE_ESCKEY) && !CAVESync->Quit) {
/* Nap in the while loop if not doing any processing,
cuts down on needless looping
*/
CAVEUSleep(10);
}
CAVEExit();
}
/* initSphereMem - initializes sphere memory. The data is allocated from a
main memory arena, and will be common to all display threads.
*/
void initSphereMem() {
sphere = (SPHEREDATA*) malloc(2*sizeof(SPHEREDATA));
#ifndef WIN32
bzero(sphere,2*sizeof(SPHEREDATA));
#else
memset(sphere,0,2*sizeof(SPHEREDATA));
#endif
}
/* frameUpdate - do the computation of the sphere in the frame update so
it's data values are synced with the draw function. Since the data
is shared we only need to update the spheres position once per frame,
hence the if(CAVEMasterDisplay()) test, this guarantees it only gets
executed once per frame regardless of the number of processes.
*/
void frameUpdate() {
if(CAVEMasterDisplay()) {
compute();
navigate();
}
CAVEDisplayBarrier();
}
/* compute - compute new positions for the spheres. The height of the
spheres
is a function of the current CAVE time.
*/
void compute() {
float t = *CAVETime;
sphere[0].y = (float) fabs(sin(t)) * 6 + 1;
sphere[1].y = (float) fabs(sin(t)) * 4 + 1;
© 2010 enter value here
CAVELib 3.2.1 User and Reference Guide
23
}
/* navigate - perform the navigation calculations. This checks the joystick
state and uses that to move and rotate. The Y position of the joystick
determines the speed of motion in the direction of the wand. The X position
of the joystick determines the speed of rotation about the CAVE's Y axis.
Joystick values in the range -.2 to .2 are ignored; this provides a dead
zone to eliminate noise. The motion is scaled by dt, the time passed since
the last call to navigate(), in order to maintain a smooth speed
irrespective of speed of rendering.
*/
void navigate(void) {
float jx, jy, dt, t;
static float prevtime = 0;
if(CAVEMasterDisplay()) {
jx=CAVE_JOYSTICK_X;
jy=CAVE_JOYSTICK_Y;
t = (float) CAVEGetTime();
dt = t - prevtime;
prevtime = t;
if (fabs(jy)>0.2) {
float wandFront[3];
CAVEGetVector(CAVE_WAND_FRONT,wandFront);
CAVENavTranslate(wandFront[0]*jy*SPEED*dt,
wandFront[1]*jy*SPEED*dt,
wandFront[2]*jy*SPEED*dt);
}
if (fabs(jx)>0.2) {
CAVENavRot(-jx*90.0f*dt,'y');
}
}
}
/* initGL - initialize GL lighting & materials */
void initGL(void) {
float redMaterial[] = { 1, 0, 0, 1 };
float blueMaterial[] = { 0, 0, 1, 1 };
/* Enable light 0*/
glEnable(GL_LIGHT0);
/* Create a thread unique display list for the red and
then the blue material
*/
redMat[CAVEUniqueIndex()] = glGenLists(1);
© 2010 enter value here
Chapter 3 - Sample Programs
24
glNewList(redMat[CAVEUniqueIndex()], GL_COMPILE);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, redMaterial);
glEndList();
blueMat[CAVEUniqueIndex()] = glGenLists(1);
glNewList(blueMat[CAVEUniqueIndex()], GL_COMPILE);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
blueMaterial);
glEndList();
/* Make a new quadric to draw a sphere */
sphereObj[CAVEUniqueIndex()] = gluNewQuadric();
}
/* drawSpheres - draw the two spheres, using the shared data for their
y coordinates
*/
void drawSpheres() {
/* Clear the screen and zbuffer */
glClearColor(0., 0., 0., 0.);
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
glEnable(GL_LIGHTING);
/* Apply the navigation transformation */
CAVENavTransform();
/* Activate the Red Material and draw a red sphere */
glCallList(redMat[CAVEUniqueIndex()]);
glPushMatrix();
glTranslatef(2.0, sphere[0].y, -5.0);
gluSphere(sphereObj[CAVEUniqueIndex()], 1.0, 8, 8);
glPopMatrix();
/* Activate the Blue Material and draw a blue sphere */
glCallList(blueMat[CAVEUniqueIndex()]);
glPushMatrix();
glTranslatef(-2.0, sphere[1].y, -5.0);
gluSphere(sphereObj[CAVEUniqueIndex()], 1.0, 8, 8);
glPopMatrix();
glDisable(GL_LIGHTING);
drawGround();
}
void drawGround(void) {
int x;
float pt[3];
glColor3ub(255, 255, 0);
for (x = -N; x <= N; x+=INCGRID) {
glBegin(GL_LINE_STRIP);
pt[0] = x; pt[1] = 0.0; pt[2] = -N;
glVertex3fv(pt);
pt[0] = x; pt[1] = 0.0; pt[2] = N;
© 2010 enter value here
CAVELib 3.2.1 User and Reference Guide
25
glVertex3fv(pt);
glEnd();
glBegin(GL_LINE_STRIP);
pt[0] = -N; pt[1] = 0.0; pt[2] = x;
glVertex3fv(pt);
pt[0] = N; pt[1] = 0.0; pt[2] = x;
glVertex3fv(pt);
glEnd();
}
}
Chapter 4 - Software Configuration
4.1 Introduction
The CAVELib configuration files lists a number of setup options for the virtual reality display
environment which may change, but which your program would not normally set. These include such
things as which walls to use, dimensions of the walls, screen sizes, and types of tracker or input
devices. When a CAVELib program starts, the function CAVEConfigure() will read the configuration
file and save the information in a global record used by the various CAVELib functions. The default,
system wide configuration file CAVE/etc/cave.config is read first. After reading this,
CAVEConfigure() will look for the file CAVE/etc/HOST.config, where HOST is the machine
name, as returned by /usr/bsd/hostname, /usr/bin/hostname, or /bin/hostname, on unix
and linux platforms. On Windows the user must have the CAVE_HOME environement variable set to
the location of the CAVELib (e.g. C:\Mechdyne\CAVELib_3.1), then the configuration files will be
read from the etc\ directory in the CAVE_HOME directory. Next, the file .caverc in the user's home
directory is read (UNIX and Linux only) followed by the file ./.caverc in the directory the application is
being executed from. Any entries in a configuration file will override the settings from the files that were
read earlier. This means that a user's .caverc file(s) should only contain those values wished to be
changed from the default. Most of the time a user will only override the "simulator" configuration
option and the "displaymode" configuration option.
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 used by default. The
configuration options that use units are: InterocularDistance, HeadSensorOffset,
WandSensorOffset, TransmitterOffset>, Origin, CAVEWidth, CAVEHeight,
SimulatorView, Units, and ProjectionData.
4.2 Configuration Keywords
ActiveSensors <sensorID> <sensorID> ...
Lists the sensors that are to be considered active. This can be used to disable certain tracker sensors
by telling the CAVELib which sensors are active, and hence ignore all others. The tracker device
drivers will typically read data from all the sensors which a tracker may have; the library, however, will
© 2010 enter value here
Chapter 4 - Software Configuration
26
only use 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. By
default if "ActiveSensors" is not defined, all sensors are considered active.
AlwaysOnTop y|n
This configuration option forces the CAVELib window to appear above any toolbars. This was added
due to issues with newer window managers on Linux. This option is on by default. When this option is
enabled the alt+tab method for cycling between windows will not work.
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".
Calibration y|n
Whether or not to use calibration for the tracker positions.
CalibrationFile <filename>
Define the file that contains the tracker calibration data.
CAVEConfig <filename>
Gives the name of an additional configuration file to read. The file is read after the user's home .
caverc but before the local directory's .caverc. If <filename> does not have 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 physical height of the CAVE. This is only used in calculating the projection data for the original
CAVE's walls (front, left, right, floor, ceiling, wall). All non-CAVE devices should use the configuration
variable ProjectionData.
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
© 2010 enter value here
27
CAVELib 3.2.1 User and Reference Guide
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). All non-CAVE
devices should use the configuration variable ProjectionData.
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: 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 buffer and
depth buffer separately. This problem also occurs in OpenGL on Reality Engines, when calling
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT).
ControllerDaemonKey <key>
Specifies the key number for the shared memory segment that is being written to by the controller
daemon process.
ControllerType <controller-type>
The type of controller being used <controller-type> should be one of "daemon", "simulator", or
"none". This determines what if anythins supplise the controller data such as buttons/joystick. The "
daemon" option is for use with an independent daemon program (such as trackd), which
communicates with the library through standard SystemV shared memory (see the
ControllerDaemonKey configuration). The "simulator" option will use the mouse and spacebar to
simulate the PC wand's buttons and joystick. "none" disallows any controller data from being used.
Any time a controller daemon is being used, such as the ones shipped with the trackd package,
"ControllerType" should be of type "daemon".
CPULock y|n
Whether to "lock" the CPUs or not. If this is "y", each CAVELib 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
remainders will all share CPU 0. CAVEExit() will un-isolate the CPUs. This requires the programs
mplock and mpunlock(in the CAVE/bin/ directory) to be compiled for the particular platform.
Because of potential security issues Mechdyne does not ship compiled versions of these applications.
© 2010 enter value here
Chapter 4 - Software Configuration
28
Note: If the CAVELib program crashes while using this option, CAVE/bin/mpunlock should be ran
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. The <mode> can be either "mono
", or "stereo". "stereo" simply informs the application to do two eye renderings. Weather it's active
stereo, passive stereo or anaglyphic stereo, is further defined with other options. In "mono" mode only
the left eye is rendered.
Distribution <method>
Selects the communication method to use for a cluster CAVELib configuration. The distribution
methods available are "none" and "tcp". The default is "none".
DistribID <id>
The ID number for a node in a clustered CAVELib configuration. This should be in the range 0 to N-1,
where N is the number of cluster nodes. The node with ID 0 is the master; the application must be
started on this node before any of the slave nodes.
DistribNodes <number>
The number of nodes that the distributed CAVE is composed of.
DistribTCPMaster <hostname>
The network host name of the master node when using a cluster configuration.
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. This is available on
UNIX systems only.
GangSwap y|n
© 2010 enter value here
29
CAVELib 3.2.1 User and Reference Guide
If this option is 'y', the application looks to see if the NVIDIA OpenGL extensions aer available on the
system. If they are, the application adds each display thread to a swap group and binds them together.
The application then does it's swap buffer synchronization through the NVIDIA Gsync hardware. If the
OpenGL extension are not found the CAVELib defaults back to using its network based sync.
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. The Network method can be "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. When used, ordinary non-multicast UDP/IP
transfers the data. Networking packets are sent to the host specified by "NetworkUDPHost", which
can be either another CAVE, or a server which re-distributes the packets to other CAVELib
applications.
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
<port-number>+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).
© 2010 enter value here
Chapter 4 - Software Configuration
30
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>
This specifies the name of the remote host to communicate with when the UDP networking method is
being used.
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 CAVELib application sees all other CAVELib applications, but it is not visible to them.
Origin <left-distance> <floor-distance> <front-distance> <units>
This specifies the origin of the CAVE's, or other canonical VR system's, coordinate system. This is
specified as the distance from three walls to the origin. For the 10' cubic 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). The "ProjectionData" configuration variable should be used for all non-canonical VR
devices.
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-32]" 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 that 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 defines 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 the CAVELib
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.
© 2010 enter value here
31
CAVELib 3.2.1 User and Reference Guide
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 CAVElib. 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.
Note: when serial tracking is true, and tracking type is simulator, the CAVELib grabs the X-events of
the mouse from pipe :0, in multi-keyboard systems this can cause erroneous data values if the
managed areas of the pipes for each keyboard are different.
SharedContext y|n
Indicates whether or not each display thread should share its OpenGL contexts. For example, this
removes the necessity of creating unique OpenGL display lists within each display thread for
applications that run with multiple display threads (i.e. multiple GPU systems). This option is no by
default to ensure it doesn't break backwards compatability with existing applications.
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
© 2010 enter value here
Chapter 4 - Software Configuration
32
the simulated Scramnet; this can be used to test distributed CAVE programs on a single machine.
Simulator y
Shorthand option for selecting full simulator mode. Using the configuration "Simulator y" is
equivalent to specifying the options "Walls Simulator", "WallDisplay simulator -1 window
", "Tracking y", "TrackerType simulator", "ControllerType 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". Note: Saying "simulator n" will merely set the flag
CAVEConfig->Simulator to 0; it will not undo any other effects of a previous setting of "simulator y"
in a configuration file.
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 quad-stereo buffering enabled (if available, check your hardware vendor). 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.
TrackerDaemonKey <key>
Specifies the key number for the shared memory segment that is being used by the tracker daemon
process.
TrackerType <name>
Which type of tracking hardware is being used. <name> should be one of "daemon", "simulator", or
"none". "daemon" selects the tracker daemon method, where tracking is done by a completely
independent program, trackd, communicating with the library through standard SystemV shared
memory (see the TrackerDaemonKey configuration). "simulator" selects a simulated tracking
system that uses keyboard and mouse controls. Since both the tracker positions and the wand
controls are handled by the tracker process, "TrackerType none" can be used to disallow checking
of any tracker data. Note: the spaceball tracker is not available in the OpenGL version of the library.
Tracking y|n
Whether or not to run the tracker process. If tracking is disabled, the head and wand are assigned to
© 2010 enter value here
33
CAVELib 3.2.1 User and Reference Guide
fixed default positions (set by "DefaultTrackerPosition" and "DefaultTrackerOrientation
"), and all the buttons and joystick values are set to 0.
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 0.5,1 0,0.5
3 1,0 1,0.5 0.5,0
WallDisplay <wall-name> <pipe#> <optional "window"> [<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", "screen1", ..., "screen31",
"simulator", "simulator1", or "simulator2".
<pipe#> is the graphics pipe displaying the specified wall. Pipe number 0 corresponds to display :0.0,
number 1 to :0.1, etc. If <pipe#> is -1, the wall will inherit your shell's DISPLAY variable, rather than
redefining it. Also, an Xdisplay (e.g. "breeze:0.0") can be specified in place of a pipe number; this
can be used to display the wall on a remote machine in place of the local hardware. On a Windows
platform 0 and -1 are the only safe values to use for the <pipe#>.
© 2010 enter value here
Chapter 4 - Software Configuration
34
<optional "window"> will force the display to appear in a bordered window. If it is not specified, the
display will appear borderless by default.
To display in a bordered window,
WallDisplay screen0 :0.0 window 640x512+0+0
To display borderless,
WallDisplay screen0 :0.0 1280x1024+0+0
<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 that can be
moved and resized. If no geometry is given, it will default to the fully 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 that 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> ...
Specifies which walls are active. <wall> can be one of "front", "left", "right", "floor", "back", "
ceiling", "screen0", "screen1", ..., "screen31", "simulator", "simulator1", or "simulator2
". The display information (see WallDisplay) must be provided for a wall to be used (the system
configuration file should already contain that information for all walls that are physically available).
The "simulator" wall selects the simulator-style display (see Section XX). 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 desk-style or other fixed screen displays that do not correspond to
one of the canonical six walls. If one is selected, the corresponding "ProjectionData" configuration
data must also be given.
WandButtons <device1> <device2> ...
Defines the button devices to read for a custom wand (see "ControllerType" above). The devices
should be GL device names, as defined in <gl/device.h>. <device1> will be read for CAVEBUTTON1,
© 2010 enter value here
35
CAVELib 3.2.1 User and Reference Guide
<device2> for CAVEBUTTON2, etc. Up to 16 buttons may be given.
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.
4.3 Legacy Configuration Keywords
The following keywords are supported in the CAVELib 2.7 and later versions for backward compatibility
purposes. Most of these calls refer to tracking and controller settings for versions of trackd prior to 4.0.
These configuration variables or their synonyms are now set in a separate tracker configuration file.
This allows continually expanding support for devices without having to update the CAVELib itself.
More information about new configuration methods can be found in the trackd section of this manual.
Note: Applying any of the below configuration variables in addition to applying the same or similar
variables in the trackd's configuration file will likely result in erroneous data.
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".
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.
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
© 2010 enter value here
Chapter 4 - Software Configuration
36
added to the position reported by the head tracker to yield the position that the CAVELib will use for
calculating eye positions and their perspective renderings.
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 rotation
is defined by an axis and an angle of rotation about 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.
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 value.
TrackerPort <portname> [<port2name>]
Name of the serial port(s) that the trackers are attached to. <portname> should be something like "
/dev/ttyd2". The Logitech tracker uses a second serial port for the wand tracker; <port2name>
identifies this port.
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.
Wand <wand-type>
This has been changed to "ControllerType", for a description see "ControllerType" above.
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.
© 2010 enter value here
37
CAVELib 3.2.1 User and Reference Guide
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.
Chapter 5 - Hardware Configurations
The CAVELib is compatible with most spatially immersive i3D displays. All CAVELib versions above
2.7 provide support for the original CAVE structure, as well as the ImmersaDesks, Reality Centers,
tiled walls and other devices of that type. This chapter is designed to provide general configuration
information for each of the aforementioned displays. Specific set-up for commercial displays is
available directly through Mechdyne, Inc. or the display manufacturer.
Before discussion of software configuration, some general background may be necessary regarding
the various components of a virtual reality display. The information below is generic and will vary from
system to system. If you are new to VR displays, this information will give you a background, and if you
are familiar with VR displays you can proceed to your type of display's configuration section.
5.1 i3D Structures
I3D Display hardware should be configured by knowledgeable system and video engineers to be fully
functional. Although some discussion is included in this manual, professional assistance is
recommended as there is a large amount of specialization in assuring that all of the components are
functioning at their highest levels. Under normal operation, most users should only be concerned with
turning on and off the different components (although, due to ongoing display research, the hardware
configuration may change occasionally, at which time your system administrator should notify you of
the changes.) The following is a description of the common equipment used in Spatially Immersive
Virtual Reality Displays.
5.1.1 Projectors and Mirrors
The projectors and the mirrors (if there are any) for the walls may be located in front of or behind the
screen depending upon the type of system. The projector for a floor is usually suspended from the
ceiling of the structure (although six-sided cubes will have the floor rear projected from the bottom).
The projectors and mirrors are very sensitive to any motion. It takes at least an hour to align and
calibrate each projector and mirror to match at the corners of a CAVE. Please be careful not to move
the projectors or mirrors if you have to walk in that area.
Never turn off the projectors unless instructed to do so. Turning the power off can affect a projector's
alignment. On most projectors you should use the standby button on the remote control to
activate/deactivate 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.
© 2010 enter value here
Chapter 5 - Hardware Configurations
38
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.
5.1.2 Stereo Glasses
To see the virtual environment in stereoscopic 3D, users wear liquid crystal shutter glasses (usually,
Stereographics' CrystalEyes). These glasses are very fragile. These glasses will usually have an on /
off switch to keep the batteries from draining when not in use. The glasses need to be turned on in
order to see in stereo. Failing to turn the glasses on is a common error for new users. Anytime demos
are given more experienced users should make sure any new users are indeed seeing in stereo. The
glasses will not work if the user is facing away from the emitters, and will turn off when not receiving
the IR signal.
5.1.3 Stereo Emitters
The stereo emitters are little white boxes placed around the edges of the CAVE. They are the devices
that emit infrared signals to synchronize the stereo glasses to the projector's update rate. They are
always on, so most users should not have to do anything with them.
5.1.4 Controller
A wand (e.g. 3D mouse) is a common controller device. The most common type of wand has three
buttons and a pressure-sensitive joystick. It is connected to a CAVELib application using a
middle-ware program, the trackd. The Mechdyne trackd supports a number of controller devices in
addition to the wands that are commercially available. Many of these controllers can be configured in a
number of ways, check the instructions that came with the hardware to determine the best set-up.
CAVELib applications can be programmed to perform a variety of navigation and interaction
techniques. Usually a controller will lend itself to a specific interaction paradigm based on its input
mechanisms. An application developer should take their controller into consideration when creating a
program because some may have many more input values then others. There is also a trackdSDK
available for end-users to create support for their own custom input controllers. Contact
[email protected] for more information about adding support for controller devices.
5.1.5 Tracking Systems
Tracking systems are used to relate movement and position in physical space to the CAVELib.
CAVELib applications require a user's head position and orientation in order to draw correct images to
the defined walls. A second sensor is usually used on the controller (wand) for interaction with the
environment, although this is not required. The trackd program supports a number of tracking devices
including Ascension Technologies Flock of Birds, Space Pad, pcBirds, Polhemus Fastrack and
Ultratrack, and Intersense IS600 and 900. Support for tracking devices is added as products enter the
market and become of interest to the community. There is also a trackdSDK available for end-users to
create support for their own custom tracking systems. Contact [email protected] for
more information about adding support for tracking devices.
© 2010 enter value here
39
CAVELib 3.2.1 User and Reference Guide
5.1.6 Workstation
Workstation terminals can be used to run full display (CAVE, desk, wall, etc.) applications or simulator
mode displays. Multiple views can also be rendered in the simulator mode, see the simulator section of
this manual for more information.
5.2 General Configuration Notes
The CAVELib uses a series of configuration files to describe the display environment. Specific
descriptions of how to define an environment are discussed below. The CAVELib assumes a standard
CAVE display as 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 may be defined in the configuration file by the "Origin" option. But this is only used
with canonical (e.g. cubic) displays. For all other VR displays the screens' projection planes are
defined in CAVE coordinates, a.k.a. relative to some origin. An origin can be defined to be anywhere.
Some origin must be decided on, in order to define the projection planes in some coordinate system. If
you wish to change the location of the origin, you must change all the configuration settings that rely on
it, such as Origin, TransmitterPosition, and ProjectionData , to name a few.
All of the walls of the CAVE share the same reference coordinate system, as shown below. The
coordinate system is a "right-handed" system (fingers on the right hand curl from +X toward +Y and
the thumb points along +Z). All locations and orientations returned by the trackers to the CAVELib
follow this convention.
Here are three recommended origins for a CAVE, an ImmersaDesk, and a RealityCentre.
5.3 Basic Configuration Display
This section refers to the configurations for use with a CAVE or canonical display. Your installation
may vary. For detailed information on the actual configuration commands, see the CAVELib Software
Configuration section of this manual.
The CAVELib follows a path of configuration files to determine the hardware configuration. The lowest
© 2010 enter value here
Chapter 5 - Hardware Configurations
40
level is the etc/cave.config file found in /usr/local/CAVE on IRIX and Linux, /opt/CAVE/ on HPUX and
SUN, and in CAVE_HOME/ on Win32. Below is an example of the cave.config file that comes with a
CAVELib distribution. If no other configuration files get setup, a CAVELib application that reads this
configuration file will run in the default simulator mode. A HOST.config file needs to be setup to display
in a specific VR device.
#
#
#
#
#
#
#
#
Generic configuration file which is loaded by all
systems, prior to host-specific &
user configuration files
Specify which CAVE walls you want to run and on which
graphics pipe Walls simulator
Display information for walls
(pipe # & (optional) window geometry)
WallDisplay
WallDisplay
WallDisplay
WallDisplay
WallDisplay
WallDisplay
WallDisplay
WallDisplay
WallDisplay
WallDisplay
simulator -1 window
simulator1 -1 window
simulator2 -1 window
desk -1 window
front -1 window
left -1 window
floor -1 window
right -1 window
back -1 window
ceiling -1 window
#######################################################
# The following will display all six walls on a
# single 1024x768 screen
#WallDisplay front 0 256x256+256+256
#WallDisplay left 0 256x256+0+256
#WallDisplay right 0 256x256+512+256
#WallDisplay back 0 256x256+768+256
#WallDisplay floor 0 256x256+256+0
#WallDisplay ceiling 0 256x256+256+512
#Walls front left right back floor ceiling
#DisplayMode mono
#TrackerType simulator
#######################################################
# Display mode - mono or stereo
DisplayMode mono
# Type of tracking (birds, polhemus, logitech,
# mouse, or simulator)
TrackerType simulator
# Serial port(s) for tracking
TrackerPort /dev/ttym2
# Baud rate for tracker
TrackerBaud 38400
# Tracker calibration (y or n)
Calibration n
# Tracker calibration file
CalibrationFile /usr/local/CAVE/etc/cave.correction.table
# Offset from head sensor to point between user's eyes
© 2010 enter value here
41
CAVELib 3.2.1 User and Reference Guide
HeadSensorOffset 0 0 0 in
# Interocular distance (in inches or cm.)
InterocularDistance 2.7500 in
# Offset from wand sensor to position reported by library
WandSensorOffset 0 0 0 in
# Origin of coordinates of the CAVE (given in distance
# to the walls)distance to left wall distance to floor
# distance to front wall
Origin 5.0 0.0 5.0 feet
# Cave width (& depth)
CAVEWidth 10.0 feet
# Cave height
CAVEHeight 10.0 feet
# Cave units for GL coordinates (Meters or feet)
Units Feet
# Isolate CPUs & lock rendering processes to them
CPULock n
# Which type of wand is being used (mouse or PC)
Wand simulator
# Whether to hide the cursor when in the CAVE windows
HideCursor n
# Size of screen & viewing distance - defines simulator
# viewing frustum
SimulatorView 10 7.5 2
TrackerDaemonKey 4126
ControllerDaemonKey 4127
# Full simulator mode
Simulator y
5.4 Canonical Displays, CAVE and Box Format Displays
This section refers to the configurations for use with a CAVE or canonical display. Your installation
may vary. For detailed information on each configuration option, see the CAVELib Software
Configuration section of this manual.
The CAVELib follows a path of configuration files to determine the hardware configuration. Below is an
example of an ir.config file that comes with a CAVELib distribution. This file will actually be renamed to
HOST.config, where HOST is the hostname of the machine. This file should be used as a basis for all
canonical VR displays.
# Base configuration file for a 2-pipe, 2-channel each system
# driving a 4 wall i3D cubic display - where each pipe
# drives two walls, with one channel per wall
#
© 2010 enter value here
Chapter 5 - Hardware Configurations
42
# Specify here which cubic walls you want to display to
Walls front left floor right
# Update the display information to reflect which pipe
# and channel's managed area is being displayed to
# which screen
WallDisplay front :0.0 1024x768+0+0
WallDisplay left :0.0 1024x768+1024+0
WallDisplay floor :0.1 1024x768+0+0
WallDisplay right :0.1 1024x768+1024+0
# Display mode - mono | stereo
DisplayMode stereo
StereoBuffer y
# Type of tracking and input (daemon or simulator)
TrackerType daemon
ControllerType daemon
SerialTracking n
# Tracker calibration (y or n)
Calibration n
# Interocular distance (in inches or cm.)
InterocularDistance 2.7500 in
# Origin of coordinates of a CAVE (given in distance to
# the walls) Change these values when using other cubic
# devices. Comment out this line when not using a cubic
# display device distance to left wall distance to floor
# distance to front wall
Origin 5.0 0.0 5.0 feet
# Cave width (& depth)
CAVEWidth 10.0 feet
# Cave height
CAVEHeight 10.0 feet
# Cave units for GL coordinates (Meters or feet)
Units Feet
# Isolate CPUs & lock rendering processes to them
CPULock n
# Whether to hide the cursor when in the CAVE windows
HideCursor y
5.5 ImmersaDesk(TM) / Desk-Type Display
This section refers to the configurations for use with an ImmersaDesk or desk-type display. Your
installation may vary. For detailed information on the actual configuration commands, see the CAVELib
Software Configuration section of this manual.
© 2010 enter value here
43
CAVELib 3.2.1 User and Reference Guide
The CAVELib follows a path of configuration files to determine the hardware configuration. Below is
the example of the idesk.config file that comes with a CAVELib distribution. This file will actually be
renamed to HOST.config, where HOST is the hostname of the machine. This file should be used as a
basis for all desk-style VR displays.
# ImmersaDesk config
Walls screen0
WallDisplay screen0 :0.0 1280x1024+0+0
DisplayMode stereo
StereoBuffer y
HideCursor y
ControllerType daemon
Wand daemon
TrackerType daemon
SerialTracking y
ProjectionData screen0 * wall -33.50 33.00 0.00 -33.50 72.40 -30.78 33.50
33.0 0 0.00 in
5.6 Holobench / Multi-Screen Desk
Here's an example of an ir.config file that was converted to support an 'L' shaped 2-screen Holobench.
# Configuration file for a 2-pipe system driving a 2
# screened Bench - one pipe drives two projectors (i.e. channels)
#
# Specify here which display walls you want to run and
# in which graphics pipe
Walls screen0 screen1
# Display information for walls (pipe # & (optional)
# window geometry)
WallDisplay screen1 :1.0 1280x1024+0+0
WallDisplay screen0 :1.0 1280x1024+0+1024
# The corners of the screens in the CAVELib
# coordinate system
ProjectionData screen0 * wall -90 90 -110 -90 200 -110 90 90 -110 cm
ProjectionData screen1 * wall 90 90 -110 90 90 0 -90 90 -110 cm
DisplayMode stereo
StereoBuffer y
# Type of tracking
TrackerType daemon
controllerType daemon
# Cave units for GL coordinates (Meters or feet)
# This needs to be set for how the application is written
Units Meters
© 2010 enter value here
Chapter 5 - Hardware Configurations
44
# Whether to hide the cursor when in the CAVE windows
HideCursor y
5.7 Reality Center / Curved Screen Display
In a curved screen setup the projectors are tuned to display in one of two ways to account for the
curvature of the screen. One mode is sometimes called "Real World" mode, but in this document the
term "Fixed Projection Point" (FPP) mode is used because we feel it is more descriptive of the setup.
The other mode the projectors can be configured for is called "SuperDesktop" (SD) mode, or
sometimes called "MegaDesktop" mode. Each of these projection modes has its pros and cons. This
document will discuss each of these modes in detail, as well as discuss how the type of projection
mode that is being used will influence the configuration of the display pipes and channels, the
CAVELib application, as well as tracking.
The configuration of curved screen display systems always seems to be a somewhat confusing task.
The main reasons for this is because there are two different display modes in which these systems
can be configured in, the display has non-planar screens, and the projected images have overlapping
blended regions. The FPP mode and the SuperDesktop mode each require the projectors to output an
image in a format that is different than the other mode. These two projection modes each have their
pros and cons, and they also affect the type of interactions that are then allowable by the display
software. One mode, FPP, can provide a perfect perspective projection, but only for a fixed viewpoint,
which eliminates the ability to do head tracking. The other mode, SuperDesktop, allows a tracked head
perspective but only for an approximated projection plane that results in various visual anomalies.
For a complete white paper on the issues with curved screen displays please email
[email protected] and ask for the Curved Screen White Paper. The remainder of this
chapter covers curved screen configurations in a very abbreviated way. Anyone wishing for more
information should contact Mechdyne.
Curved screens can be run monoscopically or in stereo, but frequently with no tracking; users are
seated, and typically interact using a flybox, a mouse and keyboard, or other typical desktop interfaces.
But this is not say that some setups aren't run with head tracking. But the draw back to a curved
screen is that head tracking can only be done with approximated view planes resulting in visual
anomolies (fish-eyed views at the edges of the screen).
5.7.1 Single Pipe Super Desktop Setup
In SuperDesktop mode the display might be driven with 1 pipe and 3 channels, or 3
completelyseparate pipes. (Note: a pipe refers to a graphics board, and a channel refers to a video
output on a graphics pipe. SGI Infinite Reality systems usually allow 2 or 8 channels per pipe. Most
other vendor hardware only has 1 or 2 channels per pipe.)
For a single pipe with three video channels each running 1280x1024 with 256 pixel overalp the IR
combination will look something like this,
© 2010 enter value here
45
CAVELib 3.2.1 User and Reference Guide
With this channel configuration the CAVELib configuration file should be setup to create a single
projection plane such that its width is the arc length of the projection screen. Imagine the projection
plane being a soup label that gets applied to a can.
Top down view of cylindrical screen, with corresponding virtual projection plane behind the
physical screen.
For a display that has a 150deg total horizontal field of view, a 12' radius, where the screen is 1' off the
ground and is 8' in height, the CAVELibn confiuguration file would like like this:
Walls screen0
WallDisplay screen0 :0.0 3328x1024+0+0
ProjectionData screen0 * wall -15.71 1.0 -12.0 -15.71 9.0 -12.0 15.71 1.0
-12.0 feet
5.7.2 Three Pipe Super Desktop Setup
In a 3-pipe Super Desktop setup, each pipe will output a single video channel, such that each will take
the place of one of the video channels in the single-pipe setup. That is, each pipe will output a single
1280x1024 or 1024x768 image, and these images must match in the overlap regions that are blended
on the screen. It's not possible to open a single window, which spans multiple pipes, so you will have
to setup the CAVELib configuration file to support multiple walls. Because the images should match
exactly where they overlap, the geometry of the CAVE walls that cover corresponding regions must be
exactly the same.
© 2010 enter value here
Chapter 5 - Hardware Configurations
46
The easiest way to do this is to do the equivalent of the single projection plane configuration described
earlier but now we will have three co-planar projection planes, like so:
For this setup the CAVELib configuration file will need to have three individual walls configured.
Assuming 1280x1024 resolution per pipe, a 256 pixel overalp, and the same dimensions as before 150
deg total HFOV, 12' radius, 8' screen 1' off the floor the configruation would look like this:
Walls screen0 screen1 screen2
WallDisplay screen0 :0.0 1280x1024+0+0
WallDisplay screen1 :1.0 1280x1024+0+0
WallDisplay screen2 :2.0 1280x1024+0+0
ProjectionData screen0 both wall -15.71 1 -12
feet
ProjectionData screen1 both wall -6.04 1 -12
feet
ProjectionData screen2 both wall
3.63 1 -12
feet
-15.71 9 -12
-3.63 1 -12
-6.04 9 -12
6.04 1 -12
3.63 9 -12
15.71 1 -12
5.7.3 Three Pipe Fixed Projection Point Setup
If the projectors are configured for a Fixed Projection Point the CAVELib configuration file needs to
change. In this type of setup head tracking can not be done since the projectors themselves are
aligned such that the view is correct for a specific viewpoint. This viewpoint is normally the radius
distance from the screen and at the center of the vertical height of the screen. In this type of setup the
projectors are assuming the video output is a projection plane that sits along the chord in front of the
screen. The projectors also overlap so that from a top-down view the virtual projection planes would be
sitting in front of the screen like this.
© 2010 enter value here
47
CAVELib 3.2.1 User and Reference Guide
For this type of setup, the projection planes need to be setup in the CAVELib configuration file to have
exactly the right corners given the dimension of the screen and the projector configuration. Below is an
example configuration file for a 3 pipe setup where the projectors are configured for this Fixed
Projetion Point mode also called "Real World" mode. In this setup the screen is a 12' radius, 8' high
and 1' off the floor. The HFOV of the projectors is 54 degrees, the offset between projectors is 50
degrees, and the VFOV is 41.05 degrees.
# Configuration file for a 3-pipe IR system driving a 3
# wall curved screen display
#
# Specify here which Display walls you want to run and
# in which graphics pipe
Walls screen0 screen1 screen2
# Display information for walls (pipe # & (optional)
# window geometry)
WallDisplay screen0 :0.0 1280x1024+0+0
WallDisplay screen1 :0.1 1280x1024+0+0
WallDisplay screen2 :0.2 1280x1024+0+0
# data for left screen
ProjectionData screen1 * wall -11.69 1.0 -2.69 -11.68 9.0 -2.69 -4.69 1.0
-11.04 feet
# data for middle wall
ProjectionData screen0 * wall -5.45 1.0 -10.69 -5.45 9.0 -10.69 5.45 1.0
-10.69 feet
# data for right wall,
ProjectionData screen2 * wall 4.69 1.0 -11.04 4.69 9.0 -11.04 11.69 1.0
-2.69 feet
# Leave the wand (sensor #1) as an active sensor, this forces the head
position to be fixed
ActiveSensors 1
# Set the head to have a FIXED position of 5.0 feet above the origin
DefaultTrackerPosition 0 5 0 feet
© 2010 enter value here
Chapter 5 - Hardware Configurations
48
5.8 Additional Configuration Options for Clusters
Configuration files for clusters requires some additional configuration options to be set in order to
cause the CAVELib application to run in cluster mode. There are settings for both the master node and
slave nodes.These additional options can be appended to the end of each machine specific
(HOST.config) configuration file. The id's will change for each node and number of nodes is dependent
upon the cluster setup. And the hostname of the master node is the node that is designated with id 0,
and it must also be the system that is running trackd if trackers and controllers are being used.
5.8.1 Master Node Configuration Settings
# Setup the distribution mechanism
Distribution TCP
AppDistribution TCP
# Total number of nodes in cluster
DistribNodes 2
# Hostname of the master node
DistribTCPMaster grover.mydomain.com
# Which port to communicate through
DistribTCPPort 6001
# '0' indicates this node is the master node
DistribID 0
5.8.2 Slave Node Configuration Settings
# Setup the distribution mechanism
Distribution TCP
AppDistribution TCP
# Total number of nodes in cluster
DistribNodes 2
# Hostname of the master node
DistribTCPMaster grover.mydomain.com
# Which port to communicate through
DistribTCPPort 6001
# '0' indicates this node is the master node
# non-zero to 'DistribNodes - 1' are the slave nodes
DistribID 1
© 2010 enter value here
49
CAVELib 3.2.1 User and Reference Guide
Chapter 6 - Functions, Data Types, and
Macros
A library of C functions, macros, and global variables were originally developed to control the operation
of the CAVE. The CAVELib takes care of all the tasks that have to be performed to correctly operate a
CAVE or other Virtual Reality Display. CAVELib 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 elements. This section describes in detail each of the routines and
macros of the CAVE library.
NOTE: The name of all CAVELib functions, macros, and global variables start with the word CAVE
(CAVEDisplay, for example).
Data Types
CAVE_WALL_ID
CAVEID
CAVE_SENSOR_ST
CAVE_CONTROLLER_ST
CAVENETID
CAVE_USER_ST
CAVELOCK
CAVECALLBACK
CAVE_ST
Macros and Variables
CAVESENSOR (i)
CAVENETSENSOR(user,i)
CAVEBUTTONn = [ 0 | 1 ]
CAVE_JOYSTICK_X
CAVE_JOYSTICK_Y
int CAVENear,CAVEFar
int CAVEEye
int CAVEWall
float* CAVEFramesPerSecond
float* CAVETime
char* CAVEVersion
CAVE_CONTROLLER_ST*CAVEController
int* CAVENumUsers
CAVE_USER_ST** CAVEUser
CAVELib Functions
void CAVEConfigure(int *argc,char **argv,char **appdefaults)
void CAVEDisplay(CAVECALLBACK function,int num_args,...)
void CAVEExit(void)
void CAVEFrameFunction(CAVECALLBACK function,int num_args,...
void CAVEInit(void)
void CAVEInitApplication(CAVECALLBACK function,int num_args,...)
void CAVEStopApplication(CAVECALLBACK function,int numargs,...)
void CAVEAddCallback(CAVEID cbtype, CAVECALLBACK function, void
*app_data)
volatile void* CAVEAllocDisplayData(size_t size)
volatile void* CAVEAllocDisplayDataByID(int id,size_t size)
int CAVEButtonChange(int button)
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
50
float CAVEConvertFromCAVEUnits(float val,CAVEID units)
float CAVEConvertToCAVEUnits(float val,CAVEID units)
void CAVEDisplayBarrier(void)
boolean CAVEDisplayDataChanged(volatile void *buf)
boolean CAVEDisplayDataChangedByID(int id)
boolean CAVEDisplayDataIDExists(int id)
void CAVEDisplaySync(void)
void CAVEDistribBarrier(int chanID)
void CAVEDistribCloseConnection(int chanID)
boolean CAVEDistribMaster(void)
int CAVEDistribNumNodes(void)
void CAVEDistribOpenConnection(int chanID)
int CAVEDistribRead(int chanID,void *buffer,size_t size)
void CAVEDistribWrite(int chanID,void *buffer,size_t size)
void CAVEFree(void *mem)
void CAVEFreeLock(CAVELOCK lock)
void CAVEGetActiveChannels(CAVEID wall[CAVE_NUM_WALL_IDS])
boolean CAVEgetbutton(CAVE_DEVICE_ID device)
volatile void* CAVEGetDisplayData(volatile void *buf, size_t *size)
volatile void* CAVEGetDisplayDataByID(int id, size_t *size)
int CAVEGetDisplayDataID(void *buf)
void CAVEGetEyePosition(CAVEID eye, float* x, float* y, float* z)
int CAVEGetFrameNumber(void)
void CAVEGetOrientation(CAVEID oname, float* angle)
void CAVEGetPipeChannels(CAVEID wall[CAVE_NUM_WALL_IDS])
void CAVEGetPosition(CAVEID posname, float* pos)
void CAVEGetSensorOrientation(CAVE_SENSOR_ST* sensor, CAVEID frame,
float* angle)
void CAVEGetSensorPosition(CAVE_SENSOR_ST* sensor, CAVEID frame, float*
pos)
void CAVEGetSensorVector(CAVE_SENSOR_ST* sensor, CAVEID vecname, float*
vec)
float CAVEGetTime(void)
long CAVEgetvaluator(CAVE_DEVICE_ID device)
void CAVEGetVector(CAVEID vectorid,float vector[3])
void CAVEGetViewport(int* origX, int* origY, int* width, int* height)
void CAVEGetWallCorners(CAVE_WALL_ID id, float* ll, float* ul, float*
lr)
void CAVEGetWallCornersEye(CAVE_WALL_ID id, CAVEID walleye, float* ll,
float* ul, float* lr)
void CAVEGetWindowGeometry(int* origX, int* origY, int* width, int*
height)
GLXContext CAVEGLXContext(void)
void CAVEHalt(void)
void CAVEHeadTransform(void)
int CAVEInStereo(void)
void* CAVEMalloc(size_t size)
boolean CAVEMasterDisplay(void)
boolean CAVEMasterWall(void)
void CAVENavConvertCAVEToWorld(float inposition[3], float
outposition[3])
void CAVENavConvertVectorCAVEToWorld(float invector[3], float
outvector[3])
void CAVENavConvertVectorWorldToCAVE(float invector[3], float
outvector[3])
void CAVENavConvertWorldToCAVE(float inposition[3], float
outposition[3])
void CAVENavGetMatrix(Matrix m)
void CAVENavInverseTransform()
void CAVENavLoadIdentity(void)
void CAVENavLoadMatrix(Matrix m)
© 2010 enter value here
51
CAVELib 3.2.1 User and Reference Guide
void CAVENavLock(void)
void CAVENavMultMatrix(Matrix m)
void CAVENavPreMultMatrix(Matrix m)
void CAVENavRot(float angle, char axis)
void CAVENavScale(float xscale, float yscale, float zscale)
void CAVENavTransform()
void CAVENavTranslate(float xtrans, float ytrans, float ztrans)
void CAVENavUnlock(void)
void CAVENavWorldRot(float angle, char axis)
void CAVENavWorldScale(float xscale, float yscale, float zscale)
void CAVENavWorldTranslate(float xtrans, float ytrans, float ztrans)
CAVE_USER_ST* CAVENetFindUser(CAVENETID id)
void CAVENetGetOrientation(volatile CAVE_USER_ST* user, CAVEID oname,
float* ori)
void CAVENetGetPosition(volatile CAVE_USER_ST* user, CAVEID posname,
float* pos)
void CAVENetGetVector(volatile CAVE_USER_ST* user, CAVEID vecname,
float* vec)
void CAVENetHeadTransform(volatile CAVE_USER_ST* user)
int CAVENetReceive(void* buf,size_t size,CAVE_USER_ST** user)
void CAVENetSend(void* data,size_t size)
void CAVENetWandTransform(volatile CAVE_USER_ST* user)
int CAVENewID(void)
CAVELOCK CAVENewLock(void)
int CAVENumPipes(void)
void CAVEPassAllDisplayData(void)
void CAVEPassDisplayData(volatile void *buf, size_t size)
void CAVEPassDisplayDataByID(int id, size_t size)
int CAVEPipeNumber(void)
CAVEID CAVEProcessType(void)
void CAVEResetTracker(void)
void CAVEScramnetFree(void* mem)
void* CAVEScramnetMalloc(size_t size)
void CAVESensorTransform(CAVE_SENSOR_ST* sensor)
void CAVESetOption(CAVEID option, int value)
void CAVESetReadLock(CAVELOCK lock)
void CAVESetWriteLock(CAVELOCK lock)
void CAVESleep(float seconds)
CAVEID CAVEUnits(void)
void CAVEUnsetReadLock(CAVELOCK lock)
void CAVEUnsetWriteLock(CAVELOCK lock)
void* CAVEUserSharedMemory(int size)
void CAVEUSleep(unsigned long microseconds)
CAVE_WALL_ID CAVEWallID(char* wallName)
char* CAVEWallName(CAVE_WALL_ID wall)
void CAVEWallTransform(void)
void CAVEWandTransform(void)
Display* CAVEXDisplay(void)
XVisualInfo* CAVEXVisualInfo(void)
Window CAVEXWindow(void)
pfCAVELib Functions
pfList* pfCAVEChannels(void)
void pfCAVEConfig(int* argc, char** argv, char** appdefaults)
void pfCAVEDCSHeadTransform(pfDCS* dcs)
void pfCAVEDCSNavTransform(pfDCS* dcs)
void pfCAVEDCSNetHeadTransform(pfDCS* dcs, volatile CAVE_USER_ST* user)
void pfCAVEDCSNetWandTransform(pfDCS *dcs, volatile CAVE_USER_ST* user)
void pfCAVEDCSWandTransform(pfDCS* dcs)
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
52
void pfCAVEDCSSensorTransform(pfDCS* dcs,CAVE_SENSOR_ST* sensor)
void pfCAVEDrawFunc(pfChanFuncType func)
void pfCAVEHalt(void)
void pfCAVEInitChannels(void)
pfChannel* pfCAVEMasterChan(void)
pfList* pfCAVEPipes(void)
void pfCAVEPostDrawFunc(pfChanFuncType func)
void pfCAVEPostFrame(void)
void pfCAVEPreDrawFunc(pfChanFuncType func)
void pfCAVEPreFrame(void)
Environment Variables
CAVE_HOME
CAVEDEBUGCONFIG
6.1 Data Types
The following data types are defined in cave_ogl.h and are used for various CAVE function arguments
or global variables.
6.1.1 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.
6.1.2 CAVEID
an enumerated type for most identifier constants other than wall names.
6.1.3 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).
© 2010 enter value here
53
CAVELib 3.2.1 User and Reference Guide
6.1.4 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
6.1.5 CAVENETID
a unique ID for a networked CAVE user
6.1.6 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.
6.1.7 CAVELOCK
an IPC lock, as returned by CAVENewLock and used by CAVESetReadLock, etc.
6.1.8 CAVECALLBACK
a pointer to a callback function (i.e. void (*)())
6.1.9 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
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
·
·
·
·
54
float *time - the current CAVE time; this is updated once per display frame
float *framesPerSecond - the current frame rate
int *numUsers - the number of networked users
CAVE_USER_ST **user - an array of pointers to the networked users' data
6.2 CAVELib Functions
Enter topic text here.
6.2.1 Basic CAVELib Functions
The following are the basic CAVE library functions which control the operation of a CAVE program.
CAVEInit, CAVEDisplay, and CAVEExit are required use by all CAVE applications; the rest are
optional.
All of these functions should be called from an application's main process; they should not be called
from a rendering thread.
6.2.1.1
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 the Software Configuration
section of this Manual 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".
6.2.1.2
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).
© 2010 enter value here
CAVELib 3.2.1 User and Reference Guide
55
CAVEDisplay can only be called after CAVEInit.
6.2.1.3
void CAVEExit(void)
Ends a CAVE program. This function will signal all the CAVE processes to halt, and then calls exit.
6.2.1.4
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.
6.2.1.5
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.
6.2.1.6
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.
6.2.1.7
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.
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
56
6.2.2 Miscellaneous CAVELib Functions
These are the functions to obtain additional information about the display system, status of the
application, or to make certain actions occur. None of these are required to create a CAVELib
application, they are to be used on an as-need basis.
6.2.2.1
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.
6.2.2.2
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.
6.2.2.3
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.
© 2010 enter value here
57
CAVELib 3.2.1 User and Reference Guide
6.2.2.4
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.
6.2.2.5
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.
6.2.2.6
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.
6.2.2.7
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.
6.2.2.8
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().
6.2.2.9
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()).
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
58
6.2.2.10 boolean CAVEDisplayDataIDExists(int id)
Returns TRUE if a display data buffer has been allocated for ID number id, FALSE if not.
6.2.2.11 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.
6.2.2.12 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.
6.2.2.13 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.
6.2.2.14 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.
6.2.2.15 int CAVEDistribNumNodes(void)
Returns the total number of nodes in the distributed CAVE. Returns 1 if distribution is not active.
6.2.2.16 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
© 2010 enter value here
59
CAVELib 3.2.1 User and Reference Guide
process on a CAVE node should open a given channel; each channel must be opened by all nodes in
a distributed CAVE.
6.2.2.17 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.
6.2.2.18 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.
6.2.2.19 void CAVEFree(void *mem)
Frees a chunk of shared memory which was allocated by CAVEMalloc().
6.2.2.20 void CAVEFreeLock(CAVELOCK lock)
Frees up a CAVE lock, releasing the shared memory that it uses. The lock should be one returned by
CAVENewLock().
6.2.2.21 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.
6.2.2.22 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
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
60
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).
6.2.2.23 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().
6.2.2.24 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()).
6.2.2.25 int CAVEGetDisplayDataID(void *buf)
Returns the ID number associated with the display data buffer buf.
6.2.2.26 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.
6.2.2.27 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().
6.2.2.28 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).
© 2010 enter value here
61
CAVELib 3.2.1 User and Reference Guide
6.2.2.29 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.
6.2.2.30 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.
6.2.2.31 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).
6.2.2.32 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.
6.2.2.33 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,
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
62
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.
6.2.2.34 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.
6.2.2.35 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.
6.2.2.36 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.
6.2.2.37 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.
6.2.2.38 void CAVEGetWallCorners(CAVE_WALL_ID id, float* ll, float* ul, float* lr)
Returns the physical corners of a wall. The arguments require an array of 3 floats. The id is the id of
the wall that the corners sould be gotten for. ll, ul, and lr are the lower left, upper left and lower right
corners' X, Y and Z components. The values are returned in the units the CAVELib is using, which can
be determined from CAVEUnits().
© 2010 enter value here
63
CAVELib 3.2.1 User and Reference Guide
6.2.2.39 void CAVEGetWallCornersEye(CAVE_WALL_ID id, CAVEID walleye, float* ll,
float* ul, float* lr)
Returns the physical corners of a wall. The arguments require an array of 3 floats. The id is the id of
the wall that the corners sould be gotten for, and walleye specifies which eye's wall. ll, ul, and lr are the
lower left, upper left and lower right corners' X, Y and Z components. The values are returned in the
units the CAVELib is using, which can be determined from CAVEUnits(). This function can be
executed outside of a display thread.
6.2.2.40 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.
6.2.2.41 GLXContext CAVEGLXContext(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().
6.2.2.42 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().
6.2.2.43 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.
6.2.2.44 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.
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
64
6.2.2.45 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.
6.2.2.46 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.
6.2.2.47 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.
6.2.2.48 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.
6.2.2.49 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.
6.2.2.50 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.
6.2.2.51 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.
© 2010 enter value here
65
CAVELib 3.2.1 User and Reference Guide
6.2.2.52 void CAVENavGetMatrix(Matrix m)
Copies the current navigation transformation matrix into m.
6.2.2.53 void CAVENavInverseTransform()
Applies the inverse of the current navigation transformation. This allows a program to switch from
navigated coordinates to physical (tracker) coordinates.
6.2.2.54 void CAVENavLoadIdentity(void)
Resets the navigation transformation matrix to identity.
6.2.2.55 void CAVENavLoadMatrix(Matrix m)
Replaces the navigation transformation matrix with the given matrix m.
6.2.2.56 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.
6.2.2.57 void CAVENavMultMatrix(Matrix m)
Post-multiplies the current navigation transformation matrix by the given matrix m.
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
66
6.2.2.58 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.
6.2.2.59 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'.
6.2.2.60 void CAVENavScale(float xscale, float yscale, float zscale)
Performs a scaling of the CAVE, adding it to the navigation transformation.
6.2.2.61 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.
6.2.2.62 void CAVENavTranslate(float xtrans, float ytrans, float ztrans)
Performs a translation of the CAVE, adding it to the navigation transformation.
6.2.2.63 void CAVENavUnlock(void)
Releases the navigation lock set by CAVENavLock().
6.2.2.64 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().
6.2.2.65 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.
© 2010 enter value here
67
CAVELib 3.2.1 User and Reference Guide
6.2.2.66 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.
6.2.2.67 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.
6.2.2.68 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).
6.2.2.69 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.
6.2.2.70 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.
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
68
6.2.2.71 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.
6.2.2.72 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.
6.2.2.73 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.
6.2.2.74 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.
6.2.2.75 int CAVENewID(void)
Returns a new, unique integer, which may be used as an ID number for display data or a distributed
CAVE channel.
6.2.2.76 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.
© 2010 enter value here
69
CAVELib 3.2.1 User and Reference Guide
6.2.2.77 int CAVENumPipes(void)
Returns the number of drawing processes ("pipes") which are active.
6.2.2.78 void CAVEPassAllDisplayData(void)
Calls CAVEPassDisplayData() for all display data that has been allocated.
6.2.2.79 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.
6.2.2.80 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()).
6.2.2.81 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.
6.2.2.82 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.
6.2.2.83 void CAVEResetTracker(void)
Signals the tracking process to reset the tracker hardware (via the SIGUSR2 signal).
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
70
6.2.2.84 void CAVEScramnetFree(void *mem)
Frees a chunk of shared memory which was allocated by CAVEScramnetMalloc().
6.2.2.85 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.
6.2.2.86 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.
6.2.2.87 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:
6.2.2.87.1 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).
© 2010 enter value here
71
CAVELib 3.2.1 User and Reference Guide
6.2.2.87.2 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.
6.2.2.87.3 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.
6.2.2.87.4 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.
6.2.2.87.5 CAVE_GL_ALPHASIZE
The number of color buffer alpha bitplanes that should be allocated when the graphics windows are
opened. The default value is 0.
6.2.2.87.6 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.
6.2.2.87.7 CAVE_GL_STENCILSIZE
The number of stencil buffer bitplanes that should be allocated when the graphics windows are
opened. The default value is 0.
6.2.2.87.8 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.
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
72
6.2.2.87.9 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.
6.2.2.87.10 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.
6.2.2.87.11 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.
6.2.2.87.12 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.
6.2.2.87.13 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.
6.2.2.87.14 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.
© 2010 enter value here
73
CAVELib 3.2.1 User and Reference Guide
6.2.2.87.15 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.
6.2.2.87.16 CAVE_SHMEM_ADDRESS
Defines the base address of the shared memory arena used by CAVEMalloc(). This defaults to
0x70000000.
6.2.2.87.17 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.
6.2.2.87.18 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.
6.2.2.87.19 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.
6.2.2.87.20 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.
6.2.2.87.21 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.
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
74
6.2.2.87.22 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.
6.2.2.88 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()).
6.2.2.89 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().
6.2.2.90 void CAVESleep(float seconds)
Sleep for specified period of time. Do not use in display processes/threads for it will hurt performance.
CAVESleep() executes Sleep() on Win32 and sleep() on UNIX, refer to the platform specific
documentation to determine its precision. This function is useful for the main process so that the
process doesn't "hog" the cpu.
6.2.2.91 CAVEID CAVEUnits(void)
Returns the CAVEID of the units the CAVELib is using to display in. Since graphics libraries are
unitless the CAVELib has a configuration option to specify what units the objects should be rendered
with.
6.2.2.92 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.
© 2010 enter value here
75
CAVELib 3.2.1 User and Reference Guide
6.2.2.93 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.
6.2.2.94 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.
6.2.2.95 void CAVEUSleep(unsigned long milliseconds)
Sleep for specified period of time. Do not use in display process/threads for it will hurt performance.
CAVEUSleep() executes Sleep() on Win32 and usleep() on UNIX, refer to the platform specific
documentation to determine its precision.This function is useful for the main process so that the
process doesn't "hog" the cpu.
6.2.2.96 CAVE_WALL_ID CAVEWallName(char* wallName)
Returns an enum type of the wall ID for a given wall name. For example, CAVEWallName("front") will
return CAVE_FRONT_WALL.
6.2.2.97 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".
6.2.2.98 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.
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
76
6.2.2.99 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.
6.2.2.100 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.
6.2.2.101 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.
6.2.2.102 Window CAVEXWindow(void)
Returns a pointer to the X window being used by the calling rendering process. This function is only
available in the OpenGL CAVE library.
6.3 CAVE Macros and Variables
CAVE macros simplify access to the wand information. The global variables provide various
information about the state of the CAVE.
6.3.1 Sensor & Controller Macros
These macros provid information about the input devices, trackers and controllers. Additionally,
there are function calls that can be used as well for the more common trackers, head and hand. These
macros come in handy when trying to access more than just the first two sensors, head and hand.
6.3.1.1
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.
© 2010 enter value here
CAVELib 3.2.1 User and Reference Guide
77
6.3.1.2
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.
6.3.1.3
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
6.3.1.4
CAVE_JOYSTICK_X
The PC-based wand has a pressure-sensitive joystick in addition to buttons. This macro along with the
CAVE_JOYSTICK_Y macro will give the X & Y coordinate values of the joystick, normalized to be in
the range [-1.0,1.0]. (Note: when the joystick is not being pressed, these values will be close to, but not
exactly, 0).
6.3.1.5
CAVE_JOYSTICK_Y
The PC-based wand has a pressure-sensitive joystick in addition to buttons. This macro along with the
CAVE_JOYSTICK_X macro will give the X & Y coordinate values of the joystick, normalized to be in
the range [-1.0,1.0]. (Note: when the joystick is not being pressed, these values will be close to, but not
exactly, 0).
6.3.2 Global Variables
The following are global variables used by the CAVE library. CAVENear and CAVEFar can be changed
by an application. The other variables are meant for information only; your program should not change
them.
6.3.2.1
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.
© 2010 enter value here
Chapter 6 - Functions, Data Types, and Macros
6.3.2.2
78
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.
6.3.2.3
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.
6.3.2.4
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.
6.3.2.5
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.
6.3.2.6
char *CAVEVersion
A string identifying the version of the CAVE library. It contains the version number and release date.
6.3.2.7
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.
6.3.2.8
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.
© 2010 enter value here
CAVELib 3.2.1 User and Reference Guide
79
6.3.2.9
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 Environment Variables
There are two Unix environment variables which can be used to customize the behavior of CAVE
programs. They are:
6.4.1 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.
6.4.2 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.
Chapter 7 - Supporting Software
There are several auxiliary programs that are used either by the CAVELib or for testing the CAVE
hardware. These programs can be found in CAVE/bin/ directory. Source for cavevars is included in
the CAVE/src/ directory.
cavevars.exe
This is a basic confidence test for the CAVELib and hardware. It displays the values of all the
CAVELib'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, color coded to have Red as the +X axis,
Green the +Y axis, and Blue the +Z axis. A blue sphere sits at the 0,5,0 position, the sphere should
© 2010 enter value here
Chapter 7 - Supporting Software
80
appear to stay static to a tracked user viewing it in stereo. The head position values (using the
CAVELib tracker vector macros) are also displayed to each screen. To exit the program, press escape
while the master display has mouse focus.
dummytrackd.exe
The dummytrackd is a small program that will make sensors move in eliptical patterns, joysticks values
to change and button presses to randomly occur. The data values will be stored in a trackd format in
shared memory with the key values specified on the command line. This program is good for testing if
the CAVELib configuration files are setup to read trackd data without requiring a user to have a trackd
tracker or controller configured and running. Here's an example command line for running the
dummytrackd,
dummytrackd -sensors 2 -valuators 2 -buttons 3 -trackerDaemonKey 4126
-controllerDaemonKey 4127
The options are -sensors <number of sensors>, -valuators <number of valuators>, -buttons <number
of buttons>, -trackerDaemonKey <shared memory key value>, -controllerDaemonKey <shared
memory key value>.
readtrackd.exe
In order to see if the trackd is indeed reading values from a tracker and controller device, readtrackd
will read the data stored in the shared memory and print the data to the terminal once per second.
readtrackd must read the same shared memory keys that the trackd is writing to. readtrackd expects
the shared memory keys for the tracker and controller to be specified on the command line. Run
./readtrackd and it will print out its usage.
run_dummytrackd.bat
A simple batch file to start the dummy trackd with the most common shared memory keys for a tracker
and controller, 4126 and 4127, respectively.
run_readtrackd.bat
A simple batch file to start the readtrackd executable with the most common shared memory keys for a
tracker and controller, 4126 and 4127, respectively.
testpattern
This program creates a number of gray scale and RGB patterns for use in the configuration and color
calibration of a multi-walled device. Patterns, directions and levels can be changed by pressing the
keyboard, the 'h' key will print out a list of buttons and their functions. The master display wall must be
in focus in order to receive keyboard presses.. This program uses the CAVELib configuration files for
display purposes.
vcredist_x64.exe
This is a package from Microsoft to provide the necessary dll files to execute CAVELib applications
compiled with Microsoft Visual Studio. This exe is already run by the installer. You need not run this
exe unless instructed to do so by Mechdyne support.
vcredist_x86.exe
This is a package from Microsoft to provide the necessary dll files to execute CAVELib applications
compiled with Microsoft Visual Studio. This exe is already run by the installer. You need not run this
exe unless instructed to do so by Mechdyne support.
© 2010 enter value here
81
CAVELib 3.2.1 User and Reference Guide
Chapter 8 - CAVELib with FLEXlm
Licensing
8.1 Introduction
The CAVELib uses FLEXlm licensing for either node-locked or floating licenses. Floating license give
CAVELib application developers greater flexibility by allowing them to run their executables on any of
the supported systems that can accses the license server. Node-locked licenses give greater security
if a site only wishes applications to be executable on specific systems.
The license server is responsible for receiving a request for a license from an application. The server
knows how many licenses are available and grants or denies a license based on that knowledge.
FLEXlm is the software that is used by the CAVELib to handle these license requests. FLEXlm is the
de-facto standard on SGI systems for software licensing, and is available on HPUX, SUN, Linux, and
WIN32 systems as well. Given the frequent use of FLEXlm many of the necessary components will
most likely already be installed on your system, if not, they are freely available from Macrovision's
website.
8.2 Benefits
This licensing mechanism allows for many benefits to the CAVELib user community. The main benefit
being that applications are no longer only node-locked. The past licensing mechanism locked an
application to a specific licensed CPU. This stifled the ability for multiple developers at a site to compile
and test applications since all developers would require access to the same machine to execute an
application. The new licensing mechanism allows for floating licenses so that developers can run their
application on any supported machine that is networked to the license server.
Another benefit of the FLEXlm licensing is that any CAVELib executables ran simultaneously by the
same user on the same host and display will only require one license. This means a developer can run
multiple simulator windows simultaneously on the same machine as a means of testing networked
CAVELib applications, without requiring more than one license.
8.3 Installing
The Mechdyne CAVELib distribution will contain the necessary license file and vendor daemon for
licensing CAVELib applications. Prior to receiving your distribution of the CAVELib, Mechdyne will have
sent you information on how to download the necessary FLEXlm executables, lmutil, and lmgrd, from
Macrovision. The latest versions are freely available from Macrovision's website at
www.globes.com/support/fnp_utilities_download.htm and are recommended to be installed in the
/usr/sbin/ directory.
The CAVELib licensing mechanism relies on the FLEXlm license manager daemon, lmgrd, which in
turn runs the vendor specific daemon(s). In the case of the CAVELib the name of the vendor daemon
is VRCO. This daemon will likely be running at all times, it is required that it be running in order for any
FLEXlm licensed CAVELib application to run.
© 2010 enter value here
Chapter 8 - CAVELib with FLEXlm Licensing
82
Your system administrator likely has experience with FLEXlm already. If more information regarding
end-user information on FLEXlm is required it is readily available at,
www.globes.com/support/flexnet_licensing_end_user_guide.pdf.
The following steps explain how to do a basic installation of the VRCO vendor daemon and VRCO
license file (VRCO and VRCO.lic respectively), and also, how to run the license manager daemon
(lmgrd) executable. If you wish to combine the VRCO license file with other existing FLEXlm license
files on your system please refer to the FLEXlm End User Manual.
Given that there are many possible ways to configure FLEXlm licensing we can not cover all of the
installation decisions available. We have outlined an example installation below with a few options that
will walk any FLEXlm neophyte through a basic installation. Any site custom installations that are more
complex are left up to the system administrator to make the necessary changes, since if they know
that they want a different FLEXlm setup then they are likely to be proficient in FLEXlm already.
Step 1 - Install the CAVELib
Follow the directions on the Mechdyne distribution page for downloading and installing your CAVELib
directories and files. They should either be installed in /usr/local/CAVE (LINUX standard,) or
C:\Program Files\Mechdyne\CAVELib_3.2 (Windows standard). We highly recommend using
one of these specified paths for your installation.
Step 2 - Install the license file (VRCO.lic)
Place the license file, VRCO.lic, in the Mechdyne/licenses/ directory. This is where CAVELib
applications expect it to be located by default. If the CAVELib directories are not on a networked file
system, then each machine wishing to use the CAVELib will need its own copy of the CAVELib and
VRCO.lic file.
WIN32 ONLY
If this is a node-locked license keep reading, else jump to Step 3, the WIN32 section, you can
now set the license file by executing any of the provided example CAVELib executables in /bin
directory, such as cavevars.exe. A dialog will appear prompting for the location of a license file
or service. Select the 'license file' option and browse and select the recently installed VRCO.lic
file. The location of the license file will be saved in the registry, and referred to for all future
CAVELib apps. You may change this setting to a new license file if needed by running the
lmtools.exe program.
Note: If you requested a node locked license you may stop here. The remaining steps are only
required for floating licenses. To check if your license is floating, cat the file and look for any of
these key words, VENDOR, DAEMON, or SERVER. If they are in the file this is a floating license
and you should continue. Otherwise it is a node-locked license and you can stop.
Step 3 - Install the VRCO vendor daemon (VRCO)
UNIX
Place the vendor daemon, VRCO, in the CAVE/licenses/ directory. This executable will either be an
SGI, Linux, or HP executable depending upon what you specified as the platform that your FLEXlm
license server will be running on. (Note: If your FLEXlm license server is running on a platform that is
different then the platform for your CAVELib, do not put the VRCO daemon in the CAVE/licenses/
directory, instead place it in one of the alternative directories, as described below.) The FLEXlm
licensing does work in heterogeneous environments as long as the systems are available on a
© 2010 enter value here
83
CAVELib 3.2.1 User and Reference Guide
common network. For example, a Linux CAVELib and an SGI CAVELib only need a single FLEXlm
license manager running, and that manager can be running on any platform we support it does not
need to be on all of them.
The vendor daemon, VRCO, must either be available via a networked file system or reside locally on
the machine that will run the license manager daemon, lmgrd. The license manager daemon, lmgrd,
must be run on the same machine that was specified as having the HOSTID that was sent to
Mechdyne for creating your licenses. If the daemon is not placed in the CAVE/licenses/ directory it
may reside in any directory. Some possible choices are /var/flexlm/, /usr/sbin/,
/usr/local/flexlm/. Make sure the daemon is executable, it if is not, run,
chmod +x VRCO
Do not attempt to execute the daemon yourself though. The daemon will be run by the FLEXlm lmgrd
executable.
If the daemon (VRCO) is not or can not be placed in the CAVE/licenses/ directory then the
VRCO.lic file must be edited to reflect its new location. In the VRCO.lic file there will be the following
line,
VENDOR VRCO /usr/local/CAVE/licenses
for Linux versions.
Edit the path after 'VENDOR VRCO' to reflect the location of the daemon.
WIN32
On Win32, Globetrotter has provided a tool, lmtools.exe, for managing licenses. This utility is provided
in the licenses\ directory.
The vendor daemon, vrco.exe, should already be in the licenses\ directory. This vendor daemon can
only be used for setting up a FLEXlm license server on a Win32. The FLEXlm licensing does work in
heterogeneous environments as long as the systems are available on a common network. For
example, a Linux CAVELib and an SGI CAVELib only need a single FLEXlm license manager running,
and that manager can be running on any platform Mechdyne supports, it does not need to be on all of
them.
The vendor daemon, VRCO, must either be available via a networked file system or reside locally on
the machine that will run the license manager daemon, lmgrd. The license manager daemon, lmgrd,
must be run on the same machine that was specified as having the HOSTID that was sent to
Mechdyne for creating your licenses. Do not attempt to execute the daemon yourself though. The
daemon will be run by the FLEXlm lmgrd executable.
Step 4 - Start The License Manager Daemon
UNIX
To star the FLEXlm licenes manager daemon and the VRCO daemon that will actually mange the
licenses go to the Mechdyne/licenses/ directory. The command to start the daemon is
lmgrd -c VRCO.lic
This should not be run as root. It is prefered to have the daemon start automatically at boot time so
that it is available to all users at all times. To learn how to have the license manager start at boot up,
© 2010 enter value here
Chapter 8 - CAVELib with FLEXlm Licensing
84
please refer to the FLEXlm End Users Guide.
WIN32
To run the FLEXlm license manager and the VRCO daemon that will manage the licenses run
lmtools.exe. You must first select that the licensing will be provided through a service. This is under the
'Service/License File' tab.
Select the 'Configuring using Services' radio button.
Then select the tab 'Configure Services'.
We'll create a new service. In the 'Service Name' text box, delete any text that's currently there and
create a new service name, e.g. 'CAVELib'.
Next click on the 'Browse' button for the 'Path to the lmgrd.exe file', this will open a file browser.
Navigate to the /licenses directory and select 'lmgrd'.
Next select the 'Browse' button for the 'Path to the license file', again navigate to the /licenses directory
and select the VRCO.lic file that you should've placed there in a previous step.
Note that you may choose to have the license daemon started at boot-up by selecting the 'Use
Services' check box, and then selecting the 'Start Server at Power Up' check box.
Finally, select 'Save Service'. After this service is configured, you may start up the license server
through the 'Start/Stop/Reread' tab. Simply select that tab, and then select 'Start Server'. Any of the
demos in the examples/ directory should run now.
The lmtools.exe is described in greater detail in the FLEXlm End Users Guide.
8.4 Terminology
license file (VRCO.lic) - A vendor supplied file. It supplies all of the information about the licenses for
the software to the vendor daemon. The end-user can only modify certain variables in this file (please
refer to the FLEXlm End User Manual), modifying the wrong variables will invalidate the licenses.
license manager daemon (lmgrd) - A FLEXlm executable, freely available from Globetrotter. It is
responsible for starting the vendor daemon, which does the actual checking in and out of licenses
specific to that vendor.
vendor daemon (VRCO) - the vendor daemon is an executable supplied by Mechdyne that handles
the requests for licenses from the application programs. The vendor daemon is never ran explicitly, it
is always started by the lmgrd application, and killed by the lmdown application.
© 2010 enter value here
85
CAVELib 3.2.1 User and Reference Guide
Chapter 9 - Bergen Sound Server &
Library
9.1 Introduction
Bergen is a very simple, freely redistributable audio server and client library. It was created by Dave
Pape at the University of Illinois Chicago for use in CAVELib applications to get around a few of the
limitations in the VSS library, the Vanilla Sound Server from NCSA (such as, VSS is not freely
distributed). But, the Bergen system does not have nearly the range of features that VSS has -- it
merely plays audio samples or loops sounds, and can vary their amplitudes; other features may be
added in time, possibly by the user community.
As with VSS, there are two basic parts to Bergen -- the client library (libbergen) and the server (snerd).
There are also some basic client programs -- bergenReset, bergenKill, and bergenDemo1, and
bergenDemo2.
9.2 Library Interface
The Bergen library is a C++ library. It consists of classes representing the connection to the server (
bergenServer) and the individual sounds (bergenSound and bergenSample). The following is a simple
demo showing how the library is used:
#include <unistd.h>
#include "bergenServer.h"
#include "bergenSample.h"
main(int argc,char **argv)
{
bergenServer * server = new bergenServer;
bergenSample * sound = new bergenSample(argv[1],server);
sound->setLoop(1);
sound->play();
sleep(1);
sound->setAmplitude(0.25);
sleep(1);
delete server;
}
9.2.1 bergenServer class
This class handles the network connection to the server (snerd). It must be created before any sound
objects can be created. Multiple bergenServer objects, talking to the same or to different servers, can
be created by a program; they will not interfere with each other. If the object fails to connect to the
server program, it will print an error message; when this happens, messages which are to be sent to
the server by sound objects will be discarded, but the client program will run without crashing. When a
sound object is created, it must be given a pointer to the server object; the server object maintains a
© 2010 enter value here
Chapter 9 - Bergen Sound Server & Library
86
list of all sounds which are created, the server will automatically delete the sounds when it is deleted
itself.
#include "bergenServer.h"
bergenServer::bergenServer(char *host=NULL)
The constructor will make a UDP network connection to the snerd server program, sending it a
"ping" message to verify the connection. The argument host, if given, is the name or IP address of
which machine snerd, the sound server, is running on; if it is not given, the value of the
environment variable BERGEN_SERVER is used; if this variable is not set, the connection is made
to the local machine. The UDP port number is 5900.
bergenServer::~bergenServer(void)
The destructor will automatically delete all sounds which are in its list of bergenSound objects
(maintained by addSound() and removeSound).
void bergenServer::setDirectory(char *dir)
Sets the default directory for sound objects. bergenSample objects will use this directory if their
sample file name does not include a path.
char * bergenServer::directory(void)
Returns the default directory name set by setDirectory().
void bergenServer::reset(void)
Re-initializes the connection to the server program, and re-creates all the sound objects (that it
manages) on the server. This can be used to reset things if snerd crashes & is restarted, or if it is
started after the bergenServer object is created.
void bergenServer::sendMessage(char *msg)
Sends the given text string to the server program. This is mostly for internal use, by the
bergenSound classes.
int bergenServer::receiveMessage(char *msg,int size)
Receive the next message sent by the server program. This is mostly for internal use, by the
bergenSound classes.
void bergenServer::addSound(bergenSound *sound)
Adds a sound to the server object's list. This is used internally, by the bergenSound class, and
should not be called by a user application.
void bergenServer::removeSound(bergenSound *sound)
Removes a sound from the server object's list. This is used internally, by the bergenSound class,
and should not be called by applications.
9.2.2 bergenSound class
This is a generic class representing any type of sound; it defines the basic sound object interface. The
actual sound objects which are created will be of subclasses of bergenSound; presently there is only
one subclass -- bergenSample.
#include "bergenSound.h"
bergenSound::bergenSound(bergenServer *server)
The constructor must be given a pointer to a server object; it will tell the server object to add this
sound to its list of sounds.
bergenSound::~bergenSound(void)
The destructor does an automatic kill before the sound object is removed.
int bergenSound::handle(void)
Returns the handle which the server program has assigned to this sound object; this is used in all
messages to the server program which control the sound.
bergenServer * bergenSound::server(void)
Returns the pointer to the server object which was given when the object was created.
© 2010 enter value here
87
CAVELib 3.2.1 User and Reference Guide
void bergenSound::setAmplitude(float amp)
Sets the sound's current amplitude; sends a message to the server program to accomplish this.
void bergenSound::play(void)
Sends a message to the server program to start playing the sound.
void bergenSound::stop(void)
Sends a message to the server program to stop playing the sound. The next time a play command
is issued, the sound will start again from the beginning.
void bergenSound::pause(void)
Sends a message to the server program to pause the sound. The next time a play command is
issued, the sound will resume from the point at which it was paused.
void bergenSound::kill(void)
Sends a message to the server program to remove the sound, and tells the server object to
remove this sound from its list. The sound object should not be used after kill() is called; this is
meant to be called from the destructor, and should not generally be used directly by applications.
9.2.3 bergenSample class
This class represents a single audio sample file; it is a subclass of bergenSound.
#include "bergenSample.h"
bergenSample::bergenSample(char *filename,bergenServer *server)
The constructor must be given the name of the sample file that the sound will play, in addition to
the server object pointer.
void bergenSample::setLoop(int loop)
Sets the sound's looping flag -- if it is non-zero, the sound will loop continuously when it is played.
9.3 snerd
snerd is the server program which the Bergen client library communicates with in order to play sounds.
Communication between clients and snerd is by UDP/IP.
Start snerd on your audio machine before running any client programs. It has one command line option
- -srate, to set the output sample rate; e.g.:
snerd -srate 22050
The default sample rate is 32000.
snerd uses the SGI audiofile library to read sample files; this means that it can play samples in any
format supported by that library (AIFF, AIFC, WAVE, etc.) It accepts 8- or 16-bit, 2's-complement or
unsigned files of any sample rate. It will automatically resample the data to 16-bits, 2's-complement at
the selected output rate. The resampling method is very crude; input files with a low sampling rate may
sound very bad if snerd is running at a much higher output rate. For best results, use 16-bit,
2's-complement sound files and run snerd at the same sample rate as that of the files. Files can have
any number of channels, but only the first channel will be played.
© 2010 enter value here
Chapter 10 - CAVELib 3.2.1 Install Guide
88
Chapter 10 - CAVELib 3.2.1 Install
Guide
This document describes the major steps involved in unpacking and setting up the CAVELib software.
This document should be used in conjunction with two other documents, the Trackd Setup document
and the CAVELib Licensing document. The order in which the CAVELib setup, Trackd setup or
CAVELib licensing is done isn't important but all three must be done prior to any CAVELib applications
running successfully, including the test application in Step Five
10.1 Step One - Hardware
The company that the display device was purchased from is generally responsible for setting up the
hardware, connecting the projectors, trackers, devices, and stereo emitters. That setup is beyond the
scope of this document. Specific questions should be addressed to the company the display device
was purchased from. Hardware questions sent to Mechdyne will be answered as best as possible
given our level of experience with the system in question but may be redirected back to the sytem
integrator or vendor.
10.2 Step Two - Installation
If this isn't a WIN32 release (WIN32 uses install shield) unpack the software. The CAVELib software
distribution comes in two parts the Execution Only Environment (EOE) and the Development Kit
(DEV). The EOE is distributed as cavelibeoe.tgz for Linux and CAVELib3.1_EOE_Install.exe for
Windows. The DEV is distributed as cavelibdev.tar on Linux and CAVELib3.2_Install.exe on Windows.
On Windows simply double-click the executable and it will start the self-extraction and installation. On
Linux there are perl scripts to aid with the installation, install_cavelibdev, and install_cavelibeoe.
In order to begin the installation of either the EOE or the DEV package run the perl script from the
same director as the CAVELib tar file.
On UNIX the installation will create a directory named CAVE. On Windows the default location will be
C:\Program Files\Mechdyne\CAVELib_3.2. If both the EOE and DEV are installed it will result in having
the subdirectories bin, doc, etc, include, lib32, lib64, licenses, and share. The basic contents of the
directories are:
bin - various support programs for setting up and running the system
doc - documentation
etc - configuration files used when running CAVELib programs
examples - OpenGL and Open Inventor example programs.
include - header files for CAVELib libraries
lib32 - 32 bit CAVELib libraries
lib64 - 64 bit CAVELib libraries
licenses - FLEXlm licensing files
share - additional software programs from other CAVELib users
This directory hierarchy should be installed in /usr/local/CAVE for Linux. If it is installed elsewhere,
© 2010 enter value here
89
CAVELib 3.2.1 User and Reference Guide
the environment variable CAVE_HOME must be set by each user to inform CAVELib programs where
to search for configuration and support files (e.g. setenv CAVE_HOME /disk/software/CAVE).
10.3 Step Three - Configuration Files
In the CAVE/etc/ directory there are several configuration files which are general starting points for
many of the popular displays.
The cave.config file is a special configuration file, it sets most of the standard options, and tells
programs to run in simulator mode by deafult. The cave.config file should never be edited.
Regarding some of the device specific configuration examples, the ideskClassic.config file is a
standard, single screen, desk-type configuration. The fourXdisplayCube.config is a sample
configurations for a system driving a fully immersive display device, using four graphics pipes. There
are many sample configuration files. Try to start with the one that most matches the display being
configured.
Depending upon the system one of these files should be renamed and edited to fit your specific
system. First, get the hostname of the machine, on UNIX platforms the command is hostname. Be
sure to use the hostname command. The CAVELib will use this command for resolving configuration
file names, and if your hostname returned by this command isn't used below, the applications will not
find the correct configuration files.
Change directory to CAVE/etc/. On a desk-style system, copy the file idesk.config to HOST.config,
where HOST is the hostname, as returned by, hostname.
When a CAVELib program starts, it will first read the generic configuration file
CAVE/etc/cave.config, and then will read HOST.config for the machine-specific settings. This
allows multiple computers running in different modes (simulator, ImmersaDesk, CAVE, etc) to share
one NFS mounted CAVE/etc/ directory. There is one obvious problem in this design - you should not
name your machine 'cave'. Both, configuration files cave.config and HOST.config need to be installed.
The default cave.config contains some standard settings that are not in the host-specific file.
The HOST.config file will need to be edited to match the VR display system's setup. Open the file
HOST.config. The first variable listed should be 'Walls',
For a cubic or canonical system list all of the walls that the system displays to; front, left, right, floor,
ceiling, or back. The order is not important.
A 4-wall CAVE e.g.
Walls front left right floor
For a multi-panel wall, curved screen or other non-orthogonal projection planes list the number of
screens; screen0, screen1, ... screen31.
A 3-screen Reality Center e.g.
Walls screen0 screen1 screen2
A desk system that only has a single projection plane can either use the variable desk, or a screen
© 2010 enter value here
Chapter 10 - CAVELib 3.2.1 Install Guide
90
number.
An ImmersiveWorkbench e.g.
Walls desk
Next each wall (aka projection) must be assigned the pipe and managed area that is going to be
displayed to it. This is done with the variable WallDisplay. WallDisplay takes 3 variables, the wall-name
as listed above, the X display, and a resolution with X and Y offsets combination.
Two walls of a CAVE where each wall uses one channel of the same pipe, the pipe will be configured
to have a managed area of 2560x1024, so each viewport/wall is described like this,
WallDisplay front :0.0 1280x1024+0+0
WallDisplay floor :0.0 1280x1024+1280+0
An example of a three screen RealityCentre where each wall uses a single Xdisplay.
WallDisplay screen0 :0.0 1280x1024+0+0
WallDisplay screen1 :0.1 1280x1024+0+0
WallDisplay screen2 :0.2 1280x1024+0+0
The CAVELib imposes no restrictions on the resolution, which pipes, or the order of pipes that are
used for the display.
Next the CAVELib must know where the projection planes, walls, are in CAVE space. This requires
assigning an origin. The origin can be anywhere, but realize that it should be someplace that makes
sense. At the center of the floor for a CAVE is most appropriate. For a desk, it's best to be on the floor
at the midpoint along the front edge of the screen. In a RealityCentre it should be on the floor at the
horizontal midpoint and roughly at the distance from the screen that users will be viewing from.
Standing at the origin facing your display the coordinate system is, +Y up, +X to the right, and using
right-hand rule (curl your right hand fingers from +X toward +Y, your extended thumb points in +Z) +Z
is pointing backwards. It's important to remember this coordinate system since calculating the
projection plane coordinates relies on it.
Figures showing a CAVE coordinate system, desk coordinate system, and a curved screen coordinate
system.
Knowing the dimensions of your display device is essential in having the CAVELib perform the
necessary projection calculations to generate a proper perspective rendering. Any errors in the
© 2010 enter value here
91
CAVELib 3.2.1 User and Reference Guide
dimensions or calculations of the projection data will result in images that don't match at the edges of
the screens or walls. When determining the projection planes, the CAVELib wants to know the
dimensions of the rectangle the projected image lies in. If the image is displayed smaller then the
available screen area, the projected image's values are what should be used.
In a canonical display, such as a CAVE, the CAVELib calculates the projection planes internally, as
long as certain variables are properly set in the HOST.config file. The three variables that must be
setup are Origin, CAVEWidth and CAVEHeight. The origin is defined with the distances to the left wall,
floor and right wall. The CAVEHeight and CAVEWidth are simply the measured dimensions of the
projected area.
For a CAVE system, with dimensions 10'x10'x10', the origin at the center of the floor, and the projected
image completely filling the screens the HOST.config variables would look like this,
Origin 5.0 0.0 5.0 feet
CAVEHeight 10.0 feet
CAVEWidth 10.feet
For non-cubic display systems these variables can be removed or commented out from the
HOST.config file. In their place the projection data for each screen specified by the Walls variable
must be supplied in its place. The projection data variable is aptly named ProjectionData. It takes the
wall-name, which eye (for HMD support), the type of display, lower left, upper left, and lower right
corners of the projected image, and the units. For HMD support, a ProjectionData configuration
variable is set up for each eye, but in a spatially immersive display both eyes use the same screen so
the ProjectionData only needs to be setup per-screen.
Here is an example of ProjectionData for a custom desk style display. The screen is 5'x4', tilted at 50
degrees (with horizontal being 0 and vertical being 90), and its front edge is 3' off the ground.
ProjectionData desk both wall -30.0 36.0 0.0 -30.0 72.8 -30.9
30.0 36.0 0.0 inches
To calculate these corners we used the dimensions of the projection area, and the screen's tilt (this
assumes that the projected image is aligned to exactly match up with the edges of the screen). The
lower left and lower right corners were simple since the screens lower edge is parallel with the X-axis,
and the edge is at Z=0 and Y=36". The upper left corner requires a little trigonometry. The upper left X
value is simply the distance of the screen's left edge from the origin, which is -30" in X. The Y value of
the upper left corner is calculated as,
Y = base_height + sin(tilt)* screen_height
Y = 36.0 + sin(50) * 48 = 72.8"
The Z value is in the negative Z direction so its calculation requires a negative sign,
Z = -cos(tilt) * screen_height
Z = -cos(50 * 48 = -30.9"
The same principles can be used to calculate the ProjectionData for any planar screen, as long as its
dimensions and location relative to the origin is known. Curved screens are calculated in a similar way,
but it must be decided where the projection plane resides. Knowing where the four corners of a
projected image hit the screen on a curved display can be used to calculate the projection data.
© 2010 enter value here
Chapter 10 - CAVELib 3.2.1 Install Guide
92
10.4 Step Four - Testing
The basic confidence test is CAVE/bin/cavevars. This is a simple CAVE program which just
displays all the standard CAVE data - the tracking, wand-state, time, and stereo information. Run
cavevars and check that the button presses and joystick movements are both reported correctly.
Check that the tracker positions (both the head and wand) look accurate, and the stereo phase is
correct (close your left eye and make sure the text "Right Eye" is readable, then close your right eye
and make sure that the text "Left Eye" is readable).
If cavevars (or another CAVE program) does not run correctly, the first thing to check is the
configuration data. The configuration files that a program will use are printed to the terminal when the
program starts; review the messages and make sure that all relevant entries appear correct. For
example, the configuration output from an ImmersaDesk, running on a machine named "breeze", with
the environment variable CAVEDEBUGCONFIG set to "FULL", is as follows:
CAVELib Multi-threaded Version 3.2 - Compiled December 19 2007
CAVE: Reading configuration file /usr/local/CAVE/etc/cave.config
CAVE: Reading configuration file /usr/local/CAVE/etc/breeze.config
****************************************************************
CAVE Configuration (full):
Active walls ..................... 1
screen7 [-1x-1+0+0] "DISPLAY=:0.0" both eye(s)
viewport:-1,-1;-1,-1/-1,-1;-1,-1
wall, corners: (-2.79,2.75,0.00) (-2.79,6.03,-2.57)
(2.79,2.75,0.00)/(-2.79,2.75,0.00)
(-2.79,6.03,-2.57) (2.79,2.75,0.00)
CAVE width ....................... 10.00 feet
CAVE height ...................... 10.00 feet
CAVE origin ...................... 5.00 0.00 5.00 feet
Display mode ..................... stereo
Stereo buffer .................... y
Interocular distance ............. 0.229 feet
CAVE translation ................. 0.000 0.000 0.000 feet
CAVE rotation matrix ............. 1.000,0.000,0.000
0.000,1.000,0.000
0.000,0.000,1.000
CAVE scale ....................... 1.000
Hide cursor ...................... y
Serialized tracking .............. y
Tracker type ..................... daemon
Tracker Daemon Key ............... 4126
Use calibration .................. y
Calibration file .................
/usr/local/CAVE/etc/clark.0.0.correction.table
Transmitter offset ............... -0.360 8.170 -1.270 feet
Transmitter orientation matrix ... 1.000,0.000,0.000
0.000,0.799,-0.602
0.000,0.602,0.799
Wand sensor offset ............... 0.000 0.000 -0.333 feet
Wand sensor orientation matrix ... 1.000,0.000,0.000
0.000,0.985,-0.174
0.000,0.174,0.985
Head sensor offset ............... 0.292 0.000 -0.208 feet
Head sensor orientation matrix ... 0.000,-1.000,0.000
1.000,0.000,0.000
0.000,0.000,1.000
© 2010 enter value here
93
CAVELib 3.2.1 User and Reference Guide
Active sensors .................. 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
Controller type .................. daemon
Controller Daemon Key ............ 4127
Simulator ........................ n
Simulator view ................... 10.000x7.500, 2.000 feet
Network .......................... none
CPU locking ...................... n
CAVE units ....................... feet
Distribution ..................... none
App Distribution ................. none
Gang swap ........................ n
Scramnet ......................... n
Sim Scramnet Key ................. 0
****************************************************************
First make sure that both cave.config and HOST.config appear at the top of the debug printout. Then
check if the configuration files are correct for your setup, review the rest of the system setup as
described in the preceding sections. Detailed description of each of the configuration variables is
available in this CAVE User's Guide.
Appendix A - CAVELib ChangeLog
3.2.1 April 2010
ALL PLATFORMS
· No release for IRIX, HP-UX, or SUN.
· FLEXlm licensing updated to version 10.8.10.
LINUX PLATFORMS
· Built with gcc 4 on Red Hat Enterprise Linux 5.
· BUGFIX - Resolved inability to debug executables with gdb.
· The default license location has changed to /usr/local/Mechdyne/licenses
WINDOWS PLATFORMS
· Built with Visual Studio 2008 Service Pack 1.
· GPUAffinity
· Enabling GPUAffinitiy disables context sharing.
· Added CAVE_GL_ALPHASIZE to specify alpha bitplanes via CAVESetOption()
· Wobulation
· The default license location has changed to C:\Program Files\Mechdyne\licenses
#######################################################################
3.2 December 21, 2007
ALL PLATFORMS
·
Released 64-bit libraries for Windows and Linux on the x86_64 architecture (does not include
IA-64 support).
© 2010 enter value here
Appendix A - CAVELib ChangeLog
94
No release for IRIX, HP-UX, or SUN
The configuration option 'GangSwap' no implements NVIDIA's swaplocking feature.
· Uses options 'y' or 'n', is no by default
· Display threads join a swap group and bind to a swap barrier
· Upon success uses NVIDIA's functionality for synchronization, if it fails defaults to
CAVELib's networked based sync.
· Removed dependency on Motif
· BUGFIX - 'SerialTracking' set to yes was causing a crash in pfCAVELib applications upon exit,
and causing the MS Visual Studio debugger to fail.
· Added support for shared OpenGL contexts between threads
· Created a new configuration option 'SharedContext'
· Uses options 'y' or 'n'
· Is 'n', no, by default to ensure backward compatibility with existing applications.
·
·
LINUX PLATFORMS
· Added a "AlwaysOnTop" Config option
· Uses options 'y' or 'n', is on, yes, by default.
· Added in response to some newer Linux windows managers not allowing windows to be on
top of the toolbar. Enabling this options causes the alt+tab feature to be disabled for the
CAVELib window.
· Does not work for pfCAVELib applications
WINDOWS PLATFORMS
· BUGFIX - Pressing 'X' key was returning 'V' key value.
#######################################################################
3.1.1 February 9, 2004
LINUX PLATFORMS
·
·
Added lib32_glibc2.2/ that includes CAVELibs built with glibc 2.2.
Rebuilt lib32/ libraries against Performer 3.1
#######################################################################
3.1.1 December 2, 2003
ALL PLATFORMS
·
CAVEWINDOW_ST struct changed back to CAVE_WINDOW_ST, this error was introduced
in 3.1.
ALL UNIX PLATFORMS
·
·
Fixed OpenGL examples' makefile.
Updated OpenInventer example makefile to be cross-platform.
WIN32 SPECIFIC
·
Created separate uninstallations for CAVELib EOE and CAVELib DEV.
#######################################################################
3.1 September 12, 2003
© 2010 enter value here
95
CAVELib 3.2.1 User and Reference Guide
ALL PLATFORMS
· Improved PC cluster frame synchronization performance.
· The WallDisplay configuration option can now take dimensions and offsets for bordered
window configurations.
· Changed the parameter to CAVEUserSharedMemory() to size_t so that addresses aren't
truncated on 64 bit compilations (preparations for Linux and Windows 64-bit support).
· Added function CAVEGetWallCornersEye(). Allows access to the the dimensions of any wall,
even outside of the display thread.
ALL UNIX PLATFORMS
·
·
Added multi-threaded capabilities: configuration, initialization and thread safety.
Added multi-threaded OpenGL libraries "_mt.lib" to distribution.
WIN32 SPECIFIC
·
·
·
·
Added support for Performer, libpfcave_ogl_MD.lib, libpfcave_ogl_MDd.lib,
libpfcave_ogl_MT.lib, and libpfcave_ogl_MTd.lib.
Bug fix - in cluster mode slave nodes did not have the correct head position for the first frame.
When this happened if the head position was coincident with a screen it started with a bad
view matrix. On Wildcat graphics cards this left the graphic card in a state where lighting would
be incorrect for all following frames. This bug was most common on the floor screen since the
head position started at 0,0,0 and that is on the floor plane.
Bug fix - tracker thread was not shutting down correctly and killing the main process. Tracker
threads now exit correctly.
Users no longer need to define the preprocessor definition _WIN
#######################################################################
3.0.3 created - September 4, 2002
ALL PLATFORMS
·
·
·
The CAVELib is now distributed in two separate components, the CAVELib Execution Only
Environment (EOE) and the CAVELib Development Package (DEV). The CAVELib EOE
contains all of the necessary configuration files, manuals and test programs, essentially all of
the pieces necessary to configure an immersive display system for running CAVELib based
applications. The CAVELib DEV contains all of the necessary files for building a CAVELib
application. It contains the header files and libraries. Each component is downloaded and
installed separately, and it is required that the EOE is installed prior to any DEV installation.
Fixed bug, simulator display mode assumed CAVEUnits were feet. This 3rd person view now
displays correctly for all CAVEUnits.
Fixed bug, CAVEGetWallCorners() now returns correct information based on the value of
CAVEEye when it CAVEGetWallCorners() is called. The program 'testpattern' uses this
function and has also been updated.
ALL PLATFORMS - CLUSTER SPECIFIC
·
Fixed bug, the application's data distribution thread for cluster applications is now being
initialized properly. This could have caused memory stomping when an apps was configured
with the "AppDistribution" config option. Seeing a CAVEDisplayBarrier ERROR message can
be a typical sign that this bug exists.
ALL UNIX PLATFORMS
·
Added semaphore clean up for applications that allocated distributed displaydata even if they
were not running in cluster mode.
© 2010 enter value here
Appendix A - CAVELib ChangeLog
·
96
Fixed a bug to clean up semaphores leftover by CAVELib cluster applications.
WIN32 SPECIFIC
·
·
·
·
Fixed bug, the tracking thread that is created when "serialTracking" is set to "no" is now
initialized properly. It was causing memory stomping to occur. Seeing a CAVEDisplayBarrier
ERROR message can be a typical sign that this bug exists.
Fixed bug, CAVENear and CAVEFar are now scaled properly per display thread if the
CAVEUnits are something other than the default feet.
Fixed bug, minus key on numeric keypad was not bing read. It works now so that it is used for
moving the 3rd person view correctly.
Fixed bug, the display thread was calling exit() causing the application to exit prematurely,
before the necessary close down actions were executed. Fixed by moving the location of the
exit() call so that CloseHandle and _endthreadex will now be called by the main thread,
ensuring proper shutdown.
IRIX SPECIFIC
·
pfCAVELib in 64-bit mode is now compiled with the fix to allow borderless windows.
#######################################################################
3.0.2 created - April 16th, 2002
IRIX & SUN SPECIFIC
·
Fixed bug to remove deadlock caused by improper usage of a semaphore.
IRIX & LINUX SPECIFIC
·
Corrected simple_pf example code to use pfCAVEHalt instead of CAVEHalt, otherwise a
semaphore is left on exit.
LINUX SPECIFIC
·
Fixed a bug for CAVENet networking UDP port creation, was not opening a port correctly.
UNIX SPECIFIC
·
Cleanup leftover semaphores when exiting from distributed apps
WIN32 SPECIFIC
·
·
·
·
'HidePointer' config option now works for Win32.
Set window(s) to foreground when created.
Set input focus to master display thread window.
Disable screensaver and energy saving monitor when CAVELib application is in foreground.
ALL PLATFORMS
·
·
·
© 2010 enter value here
Added CAVESleep and CAVEUSleep to help in writing portable code across platforms.
Added simple_distrib examples for cluster-based applications.
Added simple_oiv example to show how an OpenGL based scenegraph, e.g. OpenInventor
from TGS, might be use with the CAVELib. In this example the CAVELib handles the
multiprocessing, windowing and view perspective, and OpenInventor is used for its scene
graph and rendering engine. The TGS download of OpenInventor has a more thorough
97
CAVELib 3.2.1 User and Reference Guide
·
·
example for using OpenInventor with the CAVELib, including more functionality then shown
here.
Added battalion and vomit mountain executables as part of the example CAVELib
applications.
Updated CAVELib manual with corrections/additions/deletions.
#######################################################################
3.0.1 created - November 24th, 2001
LINUX SPECIFIC
·
Updated the cave_ogl.h header file with a linux pre-processor directive because newer
versions of g++ was complaining about some casting operations.
#######################################################################
3.0 created - September 14th, 2001
WIN32 SPECIFIC
·
·
·
·
·
CAVE_THREAD directive must be defined when compiling multithread versions of CAVELib
(currently Win32 only)
Fix bug on Win32 so that windows are of the desired size, was previously not taking
decorations into account.
Added new macros to cave_ogl.h for various indexes of processes/threads within CAVELib,
such as CAVE_DISPLAY_BASE_INDEX. Useful for indexing into storage for individual
threads/processes. These are intended to replace the old macros in the 2.8 release, which are
still maintained for backward compatibility, but are deprecated.
Added an initializtion of the globals for CAVEFar, CAVENear, CAVEWall and CAVEEye with
initial values so they can be safely be access before CAVEConfigure() is called.
Change directory structure to match 3.0 release
· lib/ -> lib32/
· doc/examples/OpenGL -> simple_ogl
· src/CAVEB3/ -> examples/battalion/
· src/vomit/ -> examples/vomit/
· src/simple/ deleted
· demos/ deleted
· everything in bin/ deleted except cavevars.exe
· add more example config files to etc/
ALL PLATFORMS
·
·
·
·
·
·
·
·
·
·
Libraries compiled with IRIS GL are no longer included.
Libraries for the o32 bit ABI are no longer included.
Since IRIS GL is no longer supported cave.h has been removed. Any OpenGL CAVELib
programs that were using cave.h need to be changed to now use cave_ogl.h
pfcave.h includes cave_ogl.h instead of cave.h
Fixed bug so CAVEGetViewPort() returns correct size when window is resized.
Fixed bug so that only mouse events from window with current focus is used.
Added CAVEGetWallCorners() function to return the physical corners of the screens from the
configuration file.
Added CAVEUnits() function for returning what units the CAVELib is configured for.
Added title for windowed mode indicating pipe number and screen name.
Added function CAVEWallID(char*) - this returns a a wall id, when passed a string for the
© 2010 enter value here
Appendix A - CAVELib ChangeLog
·
·
·
·
98
name of the wall that the id is desired for.
Corrected bug in CAVEScramnetMalloc; the test for leftover space was incorrect.
Modified CAVEUnsetReadLock - previously, calling it when no read-locks were set would have
put it into a "negative number of readers" state. This would then allow a reader and writer to
set locks simultaneously.
Corrected bug in CAVEipcUnsetLock - calling it on a lock which was not set would allow two
locks to go through without blocking. This function is used internally; the problem would only
be visible to applications if they called CAVENavUnlock() without having called
CAVENavLock().
Added UDP distribution method. This option will be undergoing further testing and possible
modification.
#######################################################################
2.8 created - December 19th, 2000
WIN32 SPECIFIC
·
·
·
·
Add 2 versions of CAVELib that use the debug versions of the C Run-time lib.
Rename libs to be more consistent with rest of Mechdyne products and reduce confusion.
Add a couple of #defines for indexing into distrib/tracker threads.
Fix battalion crashes.
#######################################################################
2.8 Beta 3 created - September 24th, 2000
WIN32 SPECIFIC
·
·
·
·
Bugfix - Accessing of CAVE globals such as CAVEEye resolved, see the 'CAVELib Win32
Development' docs for further details.
Bugfix - Shared memory name collisions fixed.
Bugfix - Potential deadlock when CAVE barriers used by application fixed.
Now display process and thread ID information.
#######################################################################
2.8 Beta 2 created - July 14th, 2000
#######################################################################
© 2010 enter value here