#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SOUND #include #include "AudioEnv.h" #endif typedef struct { pfVec3 prevPos,pos; pfVec3 dir; float speed; float height; pfDCS *dcs; } ball_t; void update_ball(ball_t *ball,pfNode *hole); void move_ball(ball_t *ball,pfNode *scene); void bounce_ball(ball_t *ball,pfNode *scene); void initGraphics(void); ball_t * init_ball(char *objFile); void do_navigation(void); void create_scene(pfScene **scene,pfDCS **nav_dcs); void define_earthsky(pfChannel *chan); main(int argc,char **argv) { char *sounddata=NULL; int opt; #ifdef SOUND AudioEnv *audio_env = NULL; #endif pfScene *scene; pfNode *hole; pfDCS *nav_dcs; pfChannel *masterChan; ball_t *ball=NULL; pfInit(); pfCAVEConfig(&argc,argv,NULL); while ((opt = getopt(argc,argv,"s:")) != EOF) switch (opt) { case 's': sounddata = strdup(optarg); break; } if (optind >= argc-1) { fprintf(stderr,"\nUsage: %s [-s sound] hole ball\n",argv[0]); exit(1); } pfConfig(); create_scene(&scene,&nav_dcs); nav_dcs->addChild(hole = pfdLoadFile(argv[optind])); ball = init_ball(argv[optind+1]); nav_dcs->addChild(ball->dcs); { pfSphere bsphere; scene->getBound(&bsphere); CAVENavTranslate(bsphere.center.vec[0],bsphere.center.vec[1],bsphere.center.vec[2]); } scene->setTravMask(PFTRAV_ISECT, 0xffffffff, PFTRAV_SELF|PFTRAV_DESCEND|PFTRAV_IS_CACHE, PF_OR); /* nav_dcs->addChild(ball->dcs); */ pfCAVEInitChannels(); masterChan = pfCAVEMasterChan(); masterChan->setScene(scene); /* define_earthsky(masterChan); */ /* pfCAVEPreDrawFunc((pfChanFuncType)initGraphics); */ #ifdef SOUND if ((sounddata) && (CAVEDistribMaster())) { if (!BeginSoundServer()) printf("UDP connection to sound server failed\n"); else audio_env = new AudioEnv(sounddata); } #endif while (!CAVEgetbutton(CAVE_ESCKEY)) { pfSync(); pfCAVEPreFrame(); pfFrame(); pfCAVEPostFrame(); do_navigation(); pfCAVEDCSNavTransform(nav_dcs); #ifdef SOUND if (audio_env) audio_env->Update(1); #endif update_ball(ball,hole); } #ifdef SOUND if (audio_env) { delete audio_env; EndSoundServer(); } #endif pfCAVEHalt(); pfExit(); return 0; } void update_ball(ball_t *ball,pfNode *hole) { if (CAVEButtonChange(2) == -1) { pfCAVEGetVector(CAVE_WAND_FRONT_NAV,ball->dir.vec); ball->dir[PF_Z] = 0; ball->dir.normalize(); ball->speed = 3.0f; } move_ball(ball,hole); } void move_ball(ball_t *ball,pfNode *scene) { static float prevTime=-1; float time,dt; if (prevTime < 0) prevTime = pfGetTime(); time = pfGetTime(); dt = time - prevTime; prevTime = time; ball->prevPos.copy(ball->pos); ball->pos.addScaled(ball->pos,dt*ball->speed,ball->dir); ball->dcs->setTrans(ball->pos.vec[PF_X],ball->pos.vec[PF_Y],ball->pos.vec[PF_Z]); bounce_ball(ball,scene); /* ball->speed *= .995f; */ } void bounce_ball(ball_t *ball,pfNode *scene) { pfSegSet segset; pfHit **hits[32]; segset.activeMask = 1; segset.isectMask = 0xFFFF; segset.discFunc = NULL; segset.bound = NULL; segset.mode = PFTRAV_IS_PRIM|PFTRAV_IS_NORM|PFTRAV_IS_CULL_BACK; segset.segs[0].makePts(ball->prevPos,ball->pos); if (scene->isect(&segset, hits)) { pfVec3 norm,negdir; pfMatrix xmat,rotmat; (*hits[0])->query(PFQHIT_XFORM, (float*)xmat.mat); (*hits[0])->query(PFQHIT_NORM, norm.vec); norm.xformVec(norm, xmat); negdir.scale(-1.0f,ball->dir); rotmat.makeVecRotVec(negdir,norm); norm.xformVec(norm, rotmat); ball->dir.copy(norm); ball->dir[PF_Z] = 0; ball->dir.normalize(); ball->pos.copy(ball->prevPos); /* cheap hack */ } } void initGraphics(void) { pfCullFace(PFCF_OFF); pfOverride(PFSTATE_CULLFACE, PF_ON); pfCAVEPreDrawFunc(NULL); } ball_t * init_ball(char *objFile) { ball_t *ball; pfNode *obj; pfBox bbox; if ((obj = pfdLoadFile(objFile)) == NULL) { pfCAVEHalt(); pfExit(); } ball = (ball_t *) pfMalloc(sizeof(ball_t),pfGetSharedArena()); ball->dcs = new pfDCS; ball->dcs->addChild(obj); pfuTravCalcBBox(ball->dcs, &bbox); ball->height = -bbox.min[PF_Z]; ball->pos.set(0,0,ball->height); return ball; } void do_navigation(void) { float jx=CAVE_JOYSTICK_X,jy=CAVE_JOYSTICK_Y; if (fabs(jx) > 0.2) CAVENavRot(2.5f*jx,'z'); if (fabs(jy) > 0.2) { float w[3]; pfCAVEGetVector(CAVE_WAND_FRONT,w); CAVENavTranslate(w[0]*jy/5.0f,w[1]*jy/5.0f,0.0f); } } void create_scene(pfScene **scene,pfDCS **nav_dcs) { pfLightSource *light; *scene = new pfScene; *nav_dcs = new pfDCS; (*scene)->addChild(*nav_dcs); pfGeoState *gstate = new pfGeoState; gstate->setMode(PFSTATE_ENLIGHTING, PF_ON); (*scene)->setGState(gstate); light = new pfLightSource; light->setPos(1.0f,1.0f,1.0f,0.0f); (*scene)->addChild(light); light = new pfLightSource; light->setPos(-1.0f,-0.2f,-0.2f,0.0f); (*scene)->addChild(light); } void define_earthsky(pfChannel *chan) { pfEarthSky *esky = new pfEarthSky(); esky->setMode(PFES_BUFFER_CLEAR, PFES_SKY_GRND); esky->setAttr(PFES_GRND_HT, 0.0f); esky->setColor(PFES_GRND_FAR, 0.3f, 0.1f, 0.0f, 1.0f); esky->setColor(PFES_GRND_NEAR, 0.5f, 0.3f, 0.1f, 1.0f); chan->setESky(esky); }