#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <Performer/pf/pfChannel.h>
#include <Performer/pf/pfLightSource.h>
#include <Performer/pf/pfDCS.h>
#include <Performer/pf/pfTraverser.h>
#include <Performer/pfdu.h>
#include <pfcave.h>

#include "pfVidAv.h"

#define VA_SPEED 0.10f
#define RADtoDEG (180/M_PI)

static void createScene(pfChannel *chan,int argc,char **argv);
static void loadObjects(pfGroup *parent);
static int navigate(pfTraverser *trav,void *data);

/*****  LocalVidAv is used to reference the local video avatar      ****/
/*****  Xpos, Ypos, Zpos, UProt are position and rotation variables ****/
/*****			       for the local video avatar           ****/
/*****  LocalVidAvDir & LocalVidAvBase are used when initializing   ****/
/*****			       the local video avatar               ****/

int LocalVidAv; 
float Xpos, Ypos, Zpos, UProt;

char LocalVidAvDir[256], LocalVidAvBase[256];

void updateVidAvPOS(float prevtime); /*** user-defined function which ***/
			             /*** calculates local avatar     ***/
				     /*** position		      ***/

/** the following ogl_ functions are used to perform OpenGL calls  ***/
/** which are all done in either the pfCAVEPreDrawFunc() or        ***/
/** pfCAVEPostDrawFunc() ***/
 
void ogl_update_fn(void);
void ogl_draw_fn(void);
void ogl_init_fn(void);
void ogl_POSTframe(pfChannel * trav, void * data);
void ogl_PREframe(pfChannel * trav, void * data);

pfDCS *OBJdcs;
 
/* main() - this is identical to the skeleton main of outline.c++ */
int main(int argc,char **argv)
{
 pfInit();

 va_PrePreInit();  /*** does avatar initialization, must   ****/
		   /*** be called after pfInit() and       ****/
		   /*** before pfCAVEConfig();             ****/
 
 /***  va_InitLocalAvatar initializes the local avatar, must be  ****/
 /***  called after va_PrePreInit(); and before pfCAVEConfig();  ****/
 
 sprintf(LocalVidAvDir, "%s", "/nfs/avatars");
 sprintf(LocalVidAvBase, "%s", "joe2");
  
 LocalVidAv=va_InitLocalAvatar(LocalVidAvDir, LocalVidAvBase);

 
 pfCAVEConfig(&argc,argv,NULL);
 
 
 pfMultiprocess(PFMP_APP_CULL_DRAW);
 
 pfConfig();
 pfCAVEInitChannels();
 if (CAVEConfig->Simulator)
	pfCAVEMasterChan()->getFStats()->setClass(
			PFSTATS_ALL^PFSTATSHW_ENGFXPIPE_FILL, PFSTATS_ON);
 else
	pfCAVEMasterChan()->getFStats()->setClass(PFSTATS_ALL, PFSTATS_OFF);
 createScene(pfCAVEMasterChan(),argc,argv);
 
 pfCAVEPreDrawFunc( (pfChanFuncType) ogl_PREframe);
 pfCAVEPostDrawFunc( (pfChanFuncType) ogl_POSTframe);
 
 
 while (!CAVEgetbutton(CAVE_ESCKEY))
	{
	pfSync();
	pfCAVEPreFrame();
	pfFrame();
	pfCAVEPostFrame();
	}
 CAVEHalt();
 pfExit();
 return 0;
}


static void createScene(pfChannel *chan,int ,char **)
{
 pfScene *scene;
 pfGeoState *gstate;
 pfDCS *dcs;
 
 scene = new pfScene;
 gstate = new pfGeoState;				/* Set up a base geostate for the scene */
 gstate->setMode(PFSTATE_ENLIGHTING, PF_ON);
 gstate->setMode(PFSTATE_CULLFACE, PFCF_OFF);
 scene->setGState(gstate);
 scene->addChild(new pfLightSource);			/* Add a default light */
 dcs = new pfDCS;					/* Create a DCS for navigation */
 scene->addChild(dcs);
 dcs->setTravFuncs(PFTRAV_APP,navigate,NULL);
 loadObjects(dcs);
 chan->setScene(scene);					/* Assign the scene to the channels */
}


/* loadObjects() - loads and positions floor. 
*/

static void loadObjects(pfGroup *parent)
{
 pfNode *obj;
 
    OBJdcs = new pfDCS;
    
    obj = pfdLoadFile("floor.iv");			/* Load the object */
    if (obj)
    {					/* If it succeeded, add the object to the graph */
	OBJdcs->addChild(obj);
	parent->addChild(OBJdcs);
	
	OBJdcs->setScale( 80.0, 1.0, 80.0 );
	OBJdcs->setRot( 0.0, 90.0, 0.0 );
    }
    else
    {
	pfExit();
    }
}


static int navigate(pfTraverser *trav,void *)
{
#define SPEED 2.0f
 pfDCS *navDcs = (pfDCS *) trav->getNode();		/* Get a pointer to the DCS node itself */
 float jx=CAVE_JOYSTICK_X,jy=CAVE_JOYSTICK_Y;
 if (fabs(jx) > 0.125)					/* Rotate if the joystick is pushed left or right */
	CAVENavRot(-1.0f*jx,'z');
 if (fabs(jy) > 0.125)					/* Translate if the joystick is pushed forward or back */
	{
	float w[3];
	CAVEGetVector(CAVE_WAND_FRONT,w);
	CAVENavTranslate(w[0]*jy*SPEED,w[1]*jy*SPEED,w[2]*jy*SPEED);
	}
 if ((CAVEBUTTON1) && (CAVEBUTTON3))			/* Reset navigation on secret handshake */
	CAVENavLoadIdentity();
 pfCAVEDCSNavTransform(navDcs);				/* Load the DCS with the latest navigation matrix */
 return PFTRAV_CONT;					/* Tell Performer to continue traversing */
}


/***************************                    *************************/
/****************************** avatar stuff ****************************/
/***************************                    *************************/


void ogl_init_fn()
{
    
    glClearColor(0.0, 0.0, 0.0, 0.0);
       
    
  
  /***  va_InitTex initializes avatar's texture mapping  ***/
   
  va_InitTex();
  
  /***  this next call is the only difference between the local avatars   ***/
  /***  only version and the version that has both local and remote       ***/
  /***  avatars.  technically it isn't even really needed.  if networking ***/
  /***  is not enabled (in your .caverc) then remote avatars will not be  ***/
  /***  used, but if networking is enabled, this call will prevent them   ***/
  /***  from being updated and drawn.  but if networking is enabled, be   ***/
  /***  aware that remote avatars will still be loaded.                   ***/

  va_DisableRemoteAvatars();
   
}

void  ogl_draw_fn(void)
{
  
  glPushMatrix();

    CAVENavTransform();
    va_DrawAllAvatars();  /*** draws all enabled avatars ***/
	  
  glPopMatrix(); 
  

}


void ogl_update_fn(void)
{
    static int OnFlag=1, UpdateFlag=1;
    float t=pfGetTime();
    static float prevtime=pfGetTime();
    static Button1Val, Button2Val, Button3Val;
    static float LocalAvatarScale=1.0;
    
   if (CAVEBUTTON1 && (CAVEBUTTON1!=Button1Val)) printf("Local avatars are enabled: %d\n", va_LocalAvatarIsEnabled(LocalVidAv));
   
   if (CAVEBUTTON2 && (CAVEBUTTON2!=Button2Val)) 
    {
	OnFlag=(OnFlag+1)%2;
	printf("OnFlag: %d\n", OnFlag);
	if (OnFlag) va_EnableLocalAvatar(LocalVidAv);
	else va_DisableLocalAvatar(LocalVidAv);
    }
    
    if (CAVEBUTTON3 && (CAVEBUTTON3!=Button3Val)) 
    {
	UpdateFlag=(UpdateFlag+1)%2;
	printf("UpdateFlag: %d\n", UpdateFlag);
    }
    
    Button1Val=CAVEBUTTON1;
    Button2Val=CAVEBUTTON2;
    Button3Val=CAVEBUTTON3;
    
    /*** if the specified local avatar has been loaded, is enabled ***/
    /*** and UpdateFlag is true, the user-defined function is      ***/
    /*** called and va_UpdateLocalAvatar updates the specified     ***/
    /*** avatar with its new position, etc.			   ***/
    /*** even if the avatar's position hasn't changed, the user's  ***/
    /*** positiion may have, so va_UpdateLocalAvatar should be     ***/
    /*** called whenever the avatar is enabled			   ***/

    if (CAVEgetbutton(CAVE_MINUSKEY)) 
    {
	LocalAvatarScale-=.1;
	if (LocalAvatarScale<0.0) LocalAvatarScale=0.0;
	va_SetLocalAvatarScale(LocalVidAv, LocalAvatarScale);
    }
    
    if (CAVEgetbutton(CAVE_EQUALKEY)) 
    {
	LocalAvatarScale+=.1;
	va_SetLocalAvatarScale(LocalVidAv, LocalAvatarScale);
    }


    if (va_LocalAvatarIsLoaded(LocalVidAv) && va_LocalAvatarIsEnabled(LocalVidAv) )
    {
      if(UpdateFlag) updateVidAvPOS(prevtime);
      va_UpdateLocalAvatar(LocalVidAv, Xpos, Ypos, Zpos, UProt);
    }

    /*** va_UpdateAllAvatars updates all avatars appropriately ***/
    
    va_UpdateAllAvatars();
    
    prevtime=t;
}


void ogl_PREframe(pfChannel * trav, void * )
{
    static int first=1;
    
    trav->clear();
    
    if(first)
    {
        ogl_init_fn();  /** initialize OpenGL stuff only once **/
	first=0;
    }
}

void ogl_POSTframe(pfChannel * , void * )
{
   
    ogl_update_fn();
    ogl_draw_fn();

}



void updateVidAvPOS(float prevtime)
{
    static float theta=0.0;
    float R=8.0;
    float dt,t;

    t = pfGetTime();
    dt = t - prevtime;
    
    Xpos= cos(theta) * R;
    Ypos=sin(theta) * R;
    UProt=(theta*RADtoDEG);
    theta+= VA_SPEED * dt;
    if (theta> (2*M_PI)) theta-=(2*M_PI);
        
}


Back to VideoAvatar