The CAVE Collaborative Console:
Reference Guide

VT-CAVE, University Visualization & Animation Group
Virginia Polytechnic Institute & State University
2000 Kraft Drive, Suite 2400
Blacksburg, VA 24060
1+540-231-2066
kcurry@csgrad.cs.vt.edu

Copyright © 1998, 1999 VT-CAVE
Written by: Kevin Curry, Greg Edwards and Dr. Ronald Kriz

Contents (Updated 10.16.99)


1. Overview

1.1 Choice of Input Device

1.2 Adding New Console Items

1.2.1 Console Items for Multi-user Collaborations

2. Class Hierarchies

2.1Console

2.1.1List

2.2ConsoleItem & Sub-classes

2.2.1 Radar & Sub-classes

2.2.1.1 My_fpRadar
2.2.1.2 My_tsRadar

2.2.2 ConsoleList & Sub-classes

2.2.2.1 PartList

2.3Console Functions

2.3.1 load

2.3.2 record & play

2.3.3 show & hide

2.3.4 teleport

2.3.5 tether

2.3.6 Share view




1. Overview

The CAVE Collaborative Console is a Performer-based user interface written in C/C++. It was originally created for use with LIMBO and CAVERNSoft. Within the context of Performer, OpenGL, and C++, the Collaborative Console was designed to be flexible in two significant ways:

1.1 Choice of Input Device

The Console was designed to support any type of input device. The only constraint is that the input device's signals must be translatable to the Console's command set. In most cases, this should be fairly simple. For example, the same function can be invoked just as easily through a certain fingering combination with data pinch gloves as with a keyboard shortcut or a voice command. The current release (v1.0) of the Console supports voice-activated input, menu-driven input (run the cccmenu script), as well as the wand and keyboard.


1.2 Adding new Console Items

Adding newly created console items is a simple task but does require some end-user programming. End-user programming can eventually be eliminated completely through an interactive dialogue that configures the console. In the current release (v1.0), new console items must be Performer compatible. This is because new items will indirectly inherit pfDCS through the ConsoleItem class. Conceptually, the binding to Performer is not necessary. One might only need to remove the inheritance from pfDCS in the new ConsoleItem class. The remainder of this document assumes Performer.

The Console keeps two doubly-linked lists of ConsoleObjects. The List class is a template class for which ConsoleObjects are the parameterized type. ConsoleObjects can be either ConsoleItems or CAVERNst_baseAvatar_c pointers. One list is for current_items and one is for current_users.

1.2.1: Console Items for Multi-user Collaborations

The Console can easily be extended to support a variety of tasks, through its interface. Most of the Console's current functionality is geared toward multi-user interaction. Any new ConsoleItem sub-class which is intended for use as a multi-user collaborative device should override the following virtual functions:

virtual void ConsoleItem::addUser(CAVERNst_baseAvatar_c *newUser)

virtual void ConsoleItem::removeUser(CAVERNst_baseAvatar_c *newUser)
Top

2. Class Hierarchies

The Console object is not derived from a Performer object, but individual ConsoleItems are. A generic ConsoleItem is derived from a pfDCS. The are two main types of console item: Radar and ConsoleList. Each is derived from the ConsoleItem class and inherits attributes from both ConsoleItem and pfDCS. New console items to be added should inherit the ConsoleItem class.

2.1 Console

The Console class is the heart of the CCC. It defines all of the methods required for managing ConsoleItems and for invoking the collaborative utilities supported by this application. The Console is both a container class and a class for message passing between LIMBOand the individual ConsoleItems.


Figure 1: Model of the CAVE Collaborative Console
Note: AV = avatar pointer

A seperate Console object is instantiated locally for each user when they enter the LIMBO environment. The Console object is not in shared memory and exists only for the local user. It is NOT attached to the scene. This protects the console from outside tampering. The graphical interface items (radar,list, etc.) ARE attached to the scene and are, therefore, in share memory. This is unavoidable, so we have taken as many precautions as possible elsewhere in the design.

class Console

Include Files

#include <Performer/pf/pfScene.h>
#include <Performer/pr/pfLinMath.h>
#include "list.h";
#include "console_item.h++";
#include "tether.h++";
#include "path.h++";
#include "bool.h";
#include "console_MsgMgr.h++";

Class Methods

void ConsoleInit(int argc, int argv[], pfScene *env);
void reportList(char list);
void addConsoleItem(const ConsoleItem * it);
ConsoleItem removeConsoleItem(const ConsoleItem * it);
void addUser(CAVERNst_baseAvatar_c *new_user);
void removeUser(CAVERNst_baseAvatar_c *old_user);
void invokeConsoleFunc(void (*invokeFunction)(char *), char *f_name);
void updateItem(void Update_ITEM_Attr(char *), char *it_name);
void updateUser(void Update_USER_Attr(char *), char *user_name);
void hide(const char * it);
void show(const char * it);
void highlight(char *u_name);
Path* getpath();
void startrecord(char* cmd_line);
void play(char* cmd_line);
void stop();
void pause();
void continues();
void teleport(const char *cmd_line);
void tetherSend(int which, const char *u_name);
void tetherLinkTo(const char *u_name);
void tetherDetach(const char *u_name);
MessageMgr* getmessage_manager();
void modelLoadFinished(const ModelInfo& mi);
void load(const char * file);
void unload(const char *cmd_line);


void ConsoleInit(int argc, int argv[ ], pfScene *env)

Initializes the Console; indices in argv[ ] are from an enumerated list of items found in (?console_item.h++?)

void reportList(char list)
Print the contents of the
list. list = 'i' (items) or 'u' (users) or 'o' (objects).

void addConsoleItem(const ConsoleItem * it)
Add a new ConsoleItem to the console.

ConsoleItem removeConsoleItem(const ConsoleItem * it)
Remove a ConsoleItem from the console.

void addUser(CAVERNst_baseAvatar_c *new_user)
*new_user is added to current_users and passed to each item's addUser()

void removeUser(CAVERNst_baseAvatar_c *old_user)
*old_user is removed from current_users and passed to each item's removeUser( ) the pointer is then deleted.

void invokeConsoleFunc(void (*invokeFunction)(char *), char *f_name)
Invoke the console method named *f_name

void updateItem(void Update_ITEM_Attr(char *), char *it_name)
Update a particular attribute of *it_name.

void updateUser(void Update_USER_Attr(char *), char *user_name)
Update a particular (local) attribute of *user_name

void hide(const char * it)
Hide ConsoleItem named char * it.

void show(const char * it)
Show ConsoleItem named char * it.

void highlight(char *u_name)
Not currently implemented: Highlight user named char *u_name.

Path* getpath()
Returns a path pointer.

void startrecord(char* cmd_line)
Records your position at set intervals of time to a file of your choosing. The file is placed within the ccc directory that you are running the program from.

Path* getpath()
Returns a path pointer.

void play(char* cmd_line)
Plays a recorded set of position data points obtained from the record functionality.

void stop()
Stops playing or recording the current file. You cannot pick up where it left off unless you use the pause command.

void pause()
Pauses the current playing or recording of a set of position data. You may continue recording or playing from where you left off by using he continue function.

void continues()
Continues playing or recording from the time you were paused.

void teleport(const char *cmd_line)
Moves the position of your avatar to another specified avatar or object's position.

void tetherSend(int which, const char *u_name)
This function is used as a check function for the detach and attach functionalities of a tether (to verify the current tethering status and to make sure that the other user exists). If the user wishes to attach then this function will also send a message to the user in question. By tethering, you bind your position to *u_name. Your view is still subjective, but your location changes as *u_name moves in the environment.

void tetherLinkTo(const char *u_name)
This function binds your avatar to the *u_name avatar. Your view is still subjective, but your location changes as *u_name moves in the environment.

void tetherDetach(const char *u_name)
This function detaches your tether from the *u_name.

MessageMgr* getmessage_manager()
This function returns the current users console message manager from the calling location. The console message manager is the object used to send messages between different user's consoles. Currently it is only being used for the tether functionality.

void modelLoadFinished(const ModelInfo& mi)
Assign a referencing index system in the console to a loaded model so that it may be easily unloaded later.

void load(const char * file)
Load file named char * file.

void unload(const char *cmd_line)
This function removes the model named cmd_line from the scene.

void shareview(const char *u_name)
This function sets your view to that of the avatar with *u_name.

void ownview()
This function brings your view back to your own avatar.

Sharedview* getsharedview()
This function returns the sharedview object which contains the positions of both avatars in the sharedview transaction.

To instantiate the Console, first declare an array of integers with as many indices as you have items. For example, the console currently has 3 items as shown below:

int items[3] = { egoFlatRadar, egoRadar, partList };

Then instantiate a new Console and call ConsoleInit( ) with the length of your integer array, the array itself, and a pointer to the scene.

Console *console = new Console( );
console->ConsoleInit(3, items, scene_ptr);


2.1.1 List


The List class is a generic template class for holding ConsoleObjects. Nodes on the list (ConsoleObjects) are doubly-linked for ease of manipulation. Two List objects are currently used (v1.0) to hold ConsoleObjects of either type ConsoleItem or type CAVERNst_baseAvatar_c.


Figure 2: Model of the doubly-linked List class template


class List


Include Files


Class Methods

List( );
~List( );
void Clear( );
void Append(const ConsoleObj* newObj);
ConsoleObj Remove();
void SetFirst();
void Prev();
void Next();
int GetLength() const;
void setPosition(const int position);
int IsEmpty() const;
int InList() const;
int Find(const ConsoleObj* c);
int find(const char * name);
void operator=(const List& l);

List()
Constructor.

~List()
Destructor.

void Clear()
Reintialize the list.

void Insert(const ConsoleObj* newObj)
Insert newObj behind head.

void Append(const ConsoleObj* newObj)
Append newObj in front of tail.

ConsoleObj Remove()
Remove at curr, returning the object.

void SetFirst()
Set curr = head.

void Prev()
Set curr = curr->prev.

void Next()
Set curr = curr->next.

int GetLength() const
Return length of the list.

void setPosition(const int position)
Set curr to node at position.

int IsEmpty() const
Check for an empty list. Returns 1 for true, 0 for false.

int InList() const
Bounds check for end of list. Returns 1 if curr->next != NULL, 0 otherwise.

int Find(const ConsoleObj* c)
Find the ConsoleObj by pointer comparison with curr. If ConsoleObj is found, curr->next->object will point to sought after object and the function will return 1. If ConsoleObj is not found, curr is set to the head of the list and the function will return 0;

int find(const char * name)
Find a ConsoleObj by pointer comparison with name. If name is found, curr->next->object will point to sought after object and the function will return 1. If name is not found, curr is set to the head of the list and the function will return 0;

void operator=(const List& l)
Set the list equal to l by setting head, tail, and curr equal to l.head, l.tail, and l.curr, respectively.

Top

2.2 ConsoleItem & Sub-classes


The ConsoleItem class is the parent class for all objects on the Console. In the current version (v1.0), there are two classes derived from the ConsoleItem class They are: Radar and ConsoleList, which are explained in further detail below.

class ConsoleItem : public pfDCS


Include Files

#include <Performer/pf/pfDCS.h>
#include "lim_avatar.h++";
#include "CAVERNst_baseAvatar_c.h++"



// This is the enumerated list of items recognized by the console. This can be put in a config file.
enum ItemType{ generic_item, generic_radar, egoradar, egoFlatRadar, part_list, status_panel, CONSOLE_AVATAR};


Class Methods

ItemType getItemType()
int getViewState()
void setViewState(int vs)
int ConsoleItem::operator==(const ConsoleItem& c)
virtual void addUser(CAVERNst_baseAvatar_c *new_user);
virtual void removeUser(CAVERNst_baseAvatar_c *old_user);






2.2.1 Radar & Sub-classes


The Radar class is the parent class for all of the different radar available to the Console. There are currently (v1.0) 2 radar sub-classes which are derived from this class. They are My_fpRadar and My_tsRadar. Each of the radar has a different purpose and is described in further detail below.

All Radar objects have the following in common:
Data Members

Functions

class Radar : public ConsoleItem


Include Files
#include <Performer/pfdu.h>
#include <Performer/pf/pfGeode.h>
#include <Performer/pf/pfTraverser.h>
#include <Performer/pr/pfLinMath.h>
#include <pfcave.h>
#include "console_item.h++"



Data Members
char objName[256];
pfGroup *blips;
pfVec3 *center;
pfGeode *radar;
pfGeode *you;
static pfType* classType_;
int numUsersTracked;


Class Methods
Radar(ItemType it);
~Radar();
void setCenter(pfVec3 ctr);


Overridden Methods from Parent Class: ConsoleItem
void addUser(CAVERNst_baseAvatar_c *new_user);
void removeUser(CAVERNst_baseAvatar_c *old_user);


Performer Methods

static void init(void);
static pfType* getClassType(void){ return classType_; };
virtual int app(pfTraverser*);
virtual int needsApp(void);
int isActive();





2.2.1.1 My_fpRadar

The My_fpRadar class creates a version of the FloorPlanRadarwhich is centered on the local user. All other remote collaborators and objects in the shared environment are positioned on the radar relative to the location of the local user.

class My_fpRadar : public Radar

Include Files

#include "radar.h++"


Class Methods
My_fpRadar(ItemType it);
pfGeode * createCircle(float, pfVec4, int);


Overridden Methods from Parent Class: Radar
void addUser(CAVERNst_baseAvatar_c *new_user);
void removeUser(CAVERNst_baseAvatar_c *old_user);
void Update_ALL();
void Update_ONLY(char * name, int property);


Performer Methods
static void init(void);
static pfType* getClassType(void){ return classType_; };
virtual int app(pfTraverser*);
virtual int needsApp(void);
int isActive();





2.2.1.2 My_tsRadar

The My_tsRadar class creates a version of the ThreeSpaceRadarwhich is centered on the local user. All other remote collaborators and objects in the shared environment are positioned on the radar relative to the location of the local user.

class My_tsRadar : public Radar

Include Files

#include "radar.h++"


Class Methods
My_tsRadar(ItemType it);
pfGeode * createSphere(float, pfVec4, int);


Overridden Methods from Parent Class: Radar
void addUser(CAVERNst_baseAvatar_c *new_user);
void removeUser(CAVERNst_baseAvatar_c *old_user);
void Update_ALL();
void Update_ONLY(char * name, int property);


Performer Methods

static void init(void);
static pfType* getClassType(void){ return classType_; };
virtual int app(pfTraverser*);
virtual int needsApp(void);
int isActive();





2.2.2 ConsoleList & Sub-classes


ConsoleList objects are heads-up displays of textual information about the environment. The main type of ConsoleList is defined by the PartList sub-class. This is explained in further detail below.

2.2.2.1 Participant List

The PartList class provides the interface for a heads-up text list of all collaborators sharing the environment. Each person is identified on the list by their name and their distance from the local user. Users are added to the list as soon as they enter the environment. This is done through the AddUser function, which is overridden from class ConsoleItem.
Top


class PartList : public ConsoleItem

Include Files

#include "console_item.h++"

Data Members
pfDCS *titleDCS;
pfDCS *new_avDCS;
pfText *new_avText;
pfString *new_avString;
pfText *titleText;
int num_collaborators;
pfVec3 position_;
float prevTime_;
int active_;
static pfType* classType_;
pfFont *fnt;
ItemType itemType;


Class Methods
PartList();
ItemType GetItemType() { return itemType; }
double getDistance(pfVec3, pfVec3);
void HandleNameIsect();


Overridden Methods from Parent Class: ConsoleItem
void addUser(CAVERNst_baseAvatar_c *new_user);
void removeUser(CAVERNst_baseAvatar_c *old_user);
void Update_ALL();
void Update_ONLY(char * name, int property);


Performer Methods
static void init(void);
static pfType* getClassType(void){ return classType_; };
virtual int app(pfTraverser*);
virtual int needsApp(void);
int isActive();





2.3 Console Functions


The Console Functions are all situated within the console class and call appropriate functions as needed. In the current version (v1.0), there are 5 main classes of functionality that can be used. They are loading and unloading models into the environment, Recording and Playing back avatar movements, Showing and Hiding the collaborative awareness tools (radars and participant list), Teleporting to another user or specific location and Tethering to another user in the environment. These are explained in further detail below.






2.3.1 Loading and Unloading


The load and unload functions are situated in the console class. The functions use a doubly-linked list called loadedModels to keep track of all the models. The core limbo code was modified to allow .pfb models as well as .iv models to be loaded using the console's non-sequence specific indexing system (models can now be loaded and unloaded in any order). Limbo files changed were the lim_model.c++ and lim_model.h++ files.





2.3.2 Recording and Playing


The record and play functions are called from the console function but reside within the path class. The record function takes the current avatar's position and records it to a file that the user chooses. Because it is only the position information that is recorded to a file, no actions will be remembered (e.g. loading, showing awareness tools, another avatar, etc.). The play function modifies the core limbo code (lim_main.c++) to disallow navigation and only read in the positions from a specified recorded file. Applying to all of these is the ability to pause, stop and continue. Where pause allows you to continue from where you left off and stop does not (starts over or completely stops recording).

class Path : public pfDCS

Include Files

#include <Performer/pf/pfDCS.h>
#include <Performer/pf/pfGroup.h>
#include "CAVERNst_baseAvatar_c.h++"

Class Methods

Path(const char *name); //Gives the name of the file to record to.
~Path(); // destructor.
int getpmode(); //returns the current pmode
int getrmode(); //returns the current record mode
void recordpath(); //starts recording
void stoprecordpath(); //stops recording
void continuerecordpath(); //continues recording from a paused state
void pauserecordpath(); //pauses a path recording
void playpath(); //starts playing back a path that has been loaded
void loadpath() //loads a path from the file "name" into the linked list of structs;
void stopplaypath(); //stops the playback of the path and rewinds it
void pauseplaypath(); //pauses the playback of the path
void continueplaypath(); // continues the playback of the path
void hidestatus(); //used to hide the status during flashing
void showstatus(); //displays the current record/play mode of the path
virtual int app(pfTraverser*);
virtual int needsApp(void);


Performer Methods
public:
static void init(void);
static pfType* getClassType(void){ return classType_; };
private:
static pfType* classType_;





2.3.3 Show and Hide


The show and hide functions are situated in the console class. The functions are used to display the console awareness tools by toggling the draw masking of the performer objects.




2.3.4 Teleport


The teleport function is situated in the console class and allows a person to be transported to another user or a specified position. To move to another user, it uses the participant list (the list with type CAVERst_baseAvatar_c objects) to determine if the user exists and then retrieves that person's avatar's position and sets your current avatar's position to be right beside them.




2.3.5 Tether


The tether to and detach from functions are called from the console class in addition to being their own objects defined by the Tether class. The tether function uses a message manager set-up within the console class to send messages between different user's consoles. To set-up the messaging system a series of callback functions within the console class are set. The purpose of tethering is to allow the user to attach themselves to another user and follow that avatar wherever it goes.

class Console

Callback Functions


void csTetherCB(CAVERNst_baseAvatar_c *, CAVERNplus_datapack_c *);
void crTetherCB(CAVERNplus_datapack_c *);
void cs_tConfirmCB(CAVERNst_baseAvatar_c *, CAVERNplus_datapack_c *);
void cr_tConfirmCB(CAVERNplus_datapack_c *);
void cs_tDetachCB(CAVERNst_baseAvatar_c *, CAVERNplus_datapack_c *);
void cr_tDetachCB(CAVERNplus_datapack_c *);


class Tether : public pfDCS

Include Files

#include <Performer/pfdu.h>
#include <Performer/pf/pfGeode.h>
#include <Performer/pf/pfTraverser.h>
#include <Performer/pf/pfDCS.h>
#include <Performer/pr/pfLinMath.h>
#include <pfcave.h>
#include "CAVERNst_baseAvatar_c.h++"

Class Methods

Tether();
Tether(CAVERNst_baseAvatar_c *av);
~Tether();
void drawCord(pfVec3 tetherPoint, pfScene *);
void updateCord(pfVec3 new_endPt);
void adjust(float len);
virtual int app(pfTraverser*);
virtual int needsApp(void);
int isActive();


Performer Methods

static void init(void);
static pfType* getClassType(void){ return classType_; };





2.3.6 Share view


The share view and ownview functions are called from the console class in addition to being their own objects defined by the sharedview class. The sharedview function transports your view to any other user's view, effectively allowing you to see exactly what they see. When this is done, your avatar will disappear for yourself, but for all other participants it will look as if your avatar is still in place and frozen for the duration of the sharedview function. To get back to your original avatar you can invoke the ownview command and you will be brought back to your initial starting position. There is currently no security or permissions features on this function, but the console message manager could be used to achieve this.

class Sharedview : public pfDCS

Include Files

#include <Performer/pfdu.h>
#include <Performer/pf/pfGeode.h>
#include <Performer/pf/pfTraverser.h>
#include <Performer/pf/pfDCS.h>
#include <Performer/pr/pfLinMath.h>
#include <pfcave.h>
#include "CAVERNst_baseAvatar_c.h++"
#include "bool.h"
#include <Performer/pf/pfText.h;
#include <Performer/pr/pfString.h;
#include <Performer/pr/pfObject.h;
#include "lim_global.h++"

Class Methods

Sharedview();
Sharedview(CAVERNst_baseAvatar_c *av, CAVERNst_baseAvatar_c *myav);
~Sharedview();
void get_initpos(float pos[], float headangle[], float hand[], float handAngle[]);
void removeview();
virtual int app(pfTraverser*);
virtual int needsApp(void);
int isActive();


Performer Methods

static void init(void);
static pfType* getClassType(void){ return classType_; };


Back to the CCC Homepage