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