This self-documented example is in the example subdirectory of the CAVEav distribution. It can be compiled and run to see how CAVEav works.
/*
 * This is part of the ANL/MCS/FL CAVEav distribution.
 *     written by Ivan R. Judson
 *
 */


#include 
#include 
#include 
#include 

#include 

#define DTOR(r) (( r ) * 0.01745329f )

void simple_draw(void);
void draw_func(void);
void update_wandcam_pos(void);
void update_headcam_pos(void);
int parse_args(int ac, char **av);

static CAVcam *Wandcam = NULL;
static CAVcam *Headcam = NULL;

main(int argc,char **argv)
{
  CAVEConfigure(&argc, argv, NULL);

  if(parse_args(argc, argv) < 0)
    {
      perror("Can't parse arguments!");
      CAVEExit();
    }

  CAVEInit();

  if(Wandcam != NULL)
    Wandcam->Init();
  
  if(Headcam != NULL)
    Headcam->Init();
    
  CAVEDisplay(simple_draw, 0);
    
  while (!CAVEgetbutton(CAVE_ESCKEY))
    sginap(50);

  if(Wandcam != NULL)
    delete Wandcam;

  if(Headcam != NULL)
    delete Headcam;
  
  CAVEExit();

  return(0);
}

//
// CAVEav needs the users drawing function to be wrapped in another function that
//  does the CAVEav processing, this is because the users drawing function is called 
//  by any CAVEcam's in the program, hence the possibility of an infinite loop
//
void simple_draw(void)
{
  // Capture the frame
  if(Headcam != NULL)
    Headcam->Process();

  if(Wandcam != NULL)
    Wandcam->Process();

  // Draw Scene

  draw_func();
}

//
// The users actual drawing function
//
void draw_func(void)
{
  static float r = 0.0f;

  r += 0.05f;
  if (r   > 10.0f) 
    r = 0.0f;

  // Clear the screen

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // Draw the cameras

  if(Wandcam != NULL)
    Wandcam->Draw();
  
  if(Headcam != NULL)
    Headcam->Draw();

  if(Wandcam != NULL)
    Wandcam->Draw3DGrid();

  if(Wandcam == NULL && Headcam != NULL)
    Headcam->Draw3DGrid();

  // Draw the moving object

  glTranslatef(0.0f, r, -5.0f);
  glBegin(GL_TRIANGLE_FAN);
  {
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 1.0f, 0.0f);
    
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(-1.0f, 0.0f, 0.0f);
    
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(0.0f, 0.0f, 1.0f);
    
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(1.0f, 0.0f, 0.0f);
  }
  glEnd();
}

//
// Function to update the Wandcam position and orientation
//
void update_wandcam_pos(void)
{
  float wpos[3], worientF[3], worientU[3];

  if(CAVEMasterDisplay() && CAVEEye == CAVE_LEFT_EYE)
    {
      CAVEGetPosition(CAVE_WAND, wpos);
      CAVEGetVector(CAVE_WAND_FRONT, worientF);
      CAVEGetVector(CAVE_WAND_UP, worientU);

      Wandcam->SetPosition(wpos[0], wpos[1], wpos[2]);
      Wandcam->SetFront(worientF[0], worientF[1], worientF[2]);
      Wandcam->SetUp(worientU[0], worientU[1], worientU[2]);

#ifdef DEBUG
      fprintf(stderr, "Wand Position: < %f %f %f >\n", wpos[0], wpos[1], wpos[2]);
      fprintf(stderr, "Wand Front: < %f %f %f >\n", worientF[0], worientF[1], 
	      worientF[2]);
      fprintf(stderr, "Wand Up: < %f %f %f >\n", worientU[0], worientU[1], 
	      worientU[2]);
#endif
    }
}

//
// Function to update the Headcam position and orientation
//
void update_headcam_pos(void)
{
  float hpos[3], horientF[3], horientU[3];
  float _viewmatrix[16], *_invviewmatrix;
  int i;

  if(CAVEMasterDisplay() && CAVEEye == CAVE_LEFT_EYE)
    {

      CAVEGetPosition(CAVE_HEAD, hpos);
      CAVEGetVector(CAVE_HEAD_FRONT, horientF);
      CAVEGetVector(CAVE_HEAD_UP, horientU);

      Headcam->SetPosition(hpos[0], hpos[1], hpos[2]);
      Headcam->SetFront(horientF[0], horientF[1], horientF[2]);
      Headcam->SetUp(horientU[0], horientU[1], horientU[2]);

#ifdef DEBUG
      fprintf(stderr, "Head Position: < %f %f %f >\n", hpos[0], hpos[1], hpos[2]);
      fprintf(stderr, "Head Front: < %f %f %f >\n", horientF[0], horientF[1], 
	      horientF[2]);
      fprintf(stderr, "Head Up: < %f %f %f >\n", horientU[0], horientU[1], 
	      horientU[2]);
#endif
    }
}

//
// Very ugly example routine to parse command-line arguments and 
// configure the CAVcam's accordingly.  
// USE THE GETOPT LIBRARY IF YOU CAN
//
int parse_args(int ac, char **av)
{
  int i;

  for(i = 0; i < ac; i++)
    {
      if(strcmp(av[i], "-headcam") == 0)
	{
	  if(i + 1 >= ac || av[i+1][0] == '-') {
	    perror("-headcam (No specifications, net|file)");
	  } else {
	    if(strcmp(av[i+1], "net") == 0)
	      {
		Headcam = new netCAVcam(av[i+2], atoi(av[i+3]), 24, 3072);
		Headcam->SetDrawFunc(draw_func);
		Headcam->SetUpdateFunc(update_headcam_pos);
		i += 3;
	      } else if(strcmp(av[i+1], "file") == 0) {
		Headcam = new fileCAVcam(av[i+2], atoi(av[i+3]),
					 atoi(av[i+4]), atoi(av[i+5]));
		Headcam->SetDrawFunc(draw_func);
		Headcam->SetUpdateFunc(update_headcam_pos);
		i += 5;
	      }
	  }
	} else if(strcmp(av[i], "-wandcam") == 0) {
	  if(i + 1 >= ac || av[i+1][0] == '-') {
	    perror("-wandcam (No specifications, net|file)");
	  } else {
	    if(strcmp(av[i+1], "net") == 0)
	      {
		Wandcam = new netCAVcam(av[i+2], atoi(av[i+3]), 24, 3072);
		Wandcam->SetDrawFunc(draw_func);
		Wandcam->SetUpdateFunc(update_wandcam_pos);
		i += 3;
	      } else if(strcmp(av[i+1], "file") == 0) {
		Wandcam = new fileCAVcam(av[i+2], atoi(av[i+3]),
					 atoi(av[i+4]), atoi(av[i+5]));
		Wandcam->SetDrawFunc(draw_func);
		Wandcam->SetUpdateFunc(update_wandcam_pos);
		i += 5;
	      }
	  }
	} else if(strcmp(av[i], "-usage") == 0 ||
		  strcmp(av[i], "-help") == 0) {
	  fprintf(stderr, "%s:", av[0]);
	  fprintf(stderr, "\t-head [ net  | file  ]\n");
	  fprintf(stderr, "\t : hostname port\n");
	  fprintf(stderr, "\t : filename (including path) X Y Z\n");
	  CAVEExit();
	}
    }
  return(1);
}