This program gets the IRB setup to trigger on
any new incoming data
on a key called MODEL_KEY.
When new data arrives it is exported to an external
file and then
read in by Performer. The exporting is necessary
because I don't
know of a way to get Performer to read a model
directly from memory.
If an argument is given to this program it will
attempt to open
a connection to a remote IRB. If new data is
placed at the remote
IRB it will automatically be forwarded to this
program for loading.
*/
#include "CAVERN.h++"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <Performer/pf/pfChannel.h>
#include <Performer/pf/pfEarthSky.h>
#include <Performer/pf/pfLightSource.h>
#include <Performer/pf/pfGroup.h>
#include <Performer/pfdu.h>
#include <Performer/pf/pfDCS.h>
#include <pfcave.h>
pfDCS* create_scene(pfChannel *chan);
pfDCS * load_objects(char *filename,pfDCS *parent);
int doLoad = 0;
CAVERN_irbChannel_c
*g_Channel = NULL;
CAVERN_irbLink_c
*g_Link = NULL;
CAVERN_irbKey_c
*g_modelKey = NULL;
// Handle when a channel is broken.
void channelCB(CAVERN_irbChannel_c::CAVERN_channelEvent_t
event,
CAVERN_irbChannel_c
*thisChannel,
void* userData)
{
if (event == CAVERN_irbChannel_c::BROKEN_CHANNEL)
{
cvrnMesg(NULL,"CHANNEL BROKEN!");
}
void makeChannelAndLink(char
*);
makeChannelAndLink((char*)
userData);
}
// Make a channel and a link to link the MODEL_KEY
void makeChannelAndLink(char *remoteHost)
{
CAVERN_irbKeyId_c
modelKeyId;
modelKeyId.setName("MODEL_KEY");
CAVERN_irbChannel_c::status_t channelRetStatus;
CAVERN_irbId_c
remoteIRBId;
remoteIRBId.setAddress(remoteHost);
do {
cvrnPrintf("Attempting
to Connect...\n");
g_Channel->open(&remoteIRBId,NULL,CAVERN_irbChannel_c::RELIABLE,
&channelRetStatus);
g_Channel->trigger(channelCB, (void*) remoteHost);
sleep(2);
} while(channelRetStatus != CAVERN_irbChannel_c::OK);
cvrnPrintf("Connected\n");
if (g_Channel) {
if (g_Link) delete g_Link;
/// Create a link to link the local key named MODEL_KEY with the remote
key
/// also named MODEL_KEY.
CAVERN_linkAttrib_c
linkAttribute;
g_Link = g_Channel->link(g_modelKey, &modelKeyId,&linkAttribute);
if (g_Link == NULL) {
printf("Yo dude! The link didn't work!\n");
fflush(stdout);
}
}
}
// Callback for when a new model arrives.
void newModelCB(CAVERN_irbKey_c::CAVERN_irbKeyEvent_t
event,
CAVERN_irbKey_c
*thisKey,
void* userData)
{
// pfDCS *mainGroup = (pfDCS*) userData;
int size;
CAVERN_irbKey_c::status_t
status;
thisKey->getSize(&size,
&status);
if (size) {
cvrnPrintf("DATA
ARRIVED. EXPORTING\n");
thisKey->export("tempmodel.iv", &status);
// Ordinarily I would do a performer load right
// after the export but it seems something about Performer
// really barfs. So it works on an O2 but not an Onyx2.
// So instead I signal that the model has been exported
// and let the main loop do the loading.
cvrnPrintf("EXPORTING
DONE\n");
doLoad = 1;
}
}
int main(int argc,char **argv)
{
// Initialize Performer
pfInit();
// Equivalent to CAVE Config. Must be called after pfInit()
pfCAVEConfig(&argc,argv,NULL);
// Performer config
pfConfig();
// Craetes all the channels for performer
pfCAVEInitChannels();
// Create a scene composed of objects loaded from filenames specified
// in the command line arguments.
pfDCS *mainGroup;
mainGroup = create_scene(pfCAVEMasterChan());
/// Startup CAVERN.
CAVERN_irb_c
*personalIRB = CAVERNInit(&argc,
&argv, NULL);
if (!personalIRB)
exit(1);
/// Define a local key called MODEL_KEY
CAVERN_irbKeyId_c
modelKeyId;
modelKeyId.setName("MODEL_KEY");
CAVERN_irb_c::status_t
irbStatus;
g_modelKey = personalIRB->define(&modelKeyId,
NULL, &irbStatus);
g_modelKey->trigger(newModelCB,
(void *) mainGroup);
if (argc > 1) {
/// Open the channel to a remote IRB specified on the command line.
g_Channel = personalIRB->createChannel();
makeChannelAndLink(argv[1]);
}
float rotInc = 0;
// Place the objects near the center front of the CAVE
mainGroup->setTrans(0,4,4);
while (!CAVEgetbutton(CAVE_ESCKEY))
{
// Constantly spin the objects that are loaded in.
mainGroup->setRot(0,0,rotInc++);
// If object is ready to load do it...
if (doLoad) {
pfDCS* theDCSToAdd;
cvrnPrintf("PERFORMER
LOAD\n");
theDCSToAdd = load_objects("tempmodel.iv",mainGroup);
if (theDCSToAdd)
mainGroup->addChild(theDCSToAdd);
doLoad = 0;
cvrnPrintf("PERFORMER
DONE LOAD\n");
}
// Required by performer to synch things to a certain frame rate.
pfSync();
// Updates tracker data and sets up new projects for each channel.
pfCAVEPreFrame();
// Required by performer to trigger cull and draw
pfFrame();
// Updates non latency critical data.
pfCAVEPostFrame();
}
CAVEHalt();
pfExit();
return 0;
}
pfDCS * create_scene(pfChannel *chan)
{
/* Create a pfScene */
pfScene *scene = new
pfScene;
pfGeoState *gstate
= new pfGeoState;
pfDCS *group = new
pfDCS;
/* Set up the default GeoState to specify the how the geometry is to
be displayed.
*/
gstate->setMode(PFSTATE_ENLIGHTING,
PF_ON);
gstate->setMode(PFSTATE_CULLFACE,
PFCF_OFF);
scene->setGState(gstate);
/* Add a light source to the scene as well as the dcs */
pfLightSource *myLightSource
= new pfLightSource;
myLightSource->setPos(10,10,10,1);
scene->addChild(myLightSource);
/* Add a light with default settings */
scene->addChild(new
pfLightSource);
/* Add the group, and load the objects under it */
scene->addChild(group);
// load_objects(argc,argv,group);
/* Assign the scene to the display channel */
chan->setScene(scene);
return group;
}
pfDCS * load_objects(char *filename,pfDCS *parent)
{
static float i=0;
pfNode *obj;
if (obj = pfdLoadFile(filename))
{
pfDCS *newDCS = new pfDCS;
newDCS->addChild(obj);
newDCS->setTrans(0,0,i+=1);
// parent->addChild(newDCS);
return newDCS;
}
return NULL;
}