/***********************************************************************/        /***********************************************************************/
/* FreeVR OpenGL tutorial example 12: ex12_travel.c                    */        /* FreeVR OpenGL tutorial example 13: ex13_socket.c                    */
/* Last tested with: FreeVR version 0.6a                               */        /* Last tested with: FreeVR version 0.6a                               */
/* Last Modified: May 2, 2005                                          */        /* Last Modified: July 19, 2004                                        */
/* URL: http://freevr.org                                              */        /* URL: http://freevr.org                                              */
/***********************************************************************/        /***********************************************************************/
/* This example code demonstrates a VR application program that        */        /* This example code demonstrates a VR application program that        */
/*   allows the user to fly the world using a joystick controlled      */        /*   uses socket ports to receive commands.  Allowing other            */
/*   point and fly method.                                             */        /*   applications for to give commands to a running VR application.    */
/*                                                                     */        /*                                                                     */
/*                                                                     */        /*                                                                     */
/* The new features of this example include:                           */        /* The new features of this example include:                           */
/*   - FreeVR Library functions, variables, and macros:                */        /*   - Opening a socket to which clients can connect.                  */
/*      * vrGetValuatorValue() [used for joystick interaction]         */        /*   - Parsing commands read from a socket.                            */
/*      * vrPointGetVWFromUser6sensor()    [versus the real-world]     */        /*   - App. termination (quitting) can be initiated in the world sim.  */
/*      * vrVectorGetRWFrom6sensorDir()                                */     
/*      * vrUserTravelReset()                                          */     
/*      * vrUserTravelRotateId()                                       */     
/*      * vrUserTravelTranslate3d()                                    */     
/*      * vrRenderTransformUserTravel(rendinfo)                        */     
/*   - Objects fixed with respect to the real world vs. virtual world  */     
/*      (ie. coordinate systems)                                       */     
/*                                                                     */        /*                                                                     */
/* Considerations:                                                     */        /* Considerations:                                                     */
/*   - A floor/ground helps user to maintain bearings.                 */        /*   - Sockets can be connected to using perl scripts, tcl shells,     */
/*   - Now concerned about how much time passes between sim frames.    */        /*       telnet, etc.                                                  */
/*   - Interactions between wand and objects must take place in the    */        /*   - This application uses very simple-minded parsing of incoming    */
/*      same coordinate system reference frame.                        */        /*       commands.  This is actually fine for clients such as tcl      */
                                                                                 /*       shells, voice commands sent via telnet, etc.  It is primarily */
                                                                                 /*       direct human typing for which more robust parsing is material.*/
                                                                                 /*   - The entire message string is assumed to come in one chunk.      */
                                                                                 /*   - Only one client can connect at a time.                          */
/*                                                                     */        /*                                                                     */
/* This application uses the files:                                    */        /* This application uses the files:                                    */
/*   - shapes.c  (Bill Sherman's simple OpenGL shapes)                 */        /*   - shapes.c  (Bill Sherman's simple OpenGL shapes)                 */
/*                                                                     */        /*                                                                     */
/* Copyright 2010, William R. Sherman, All Rights Reserved.            */        /* Copyright 2010, William R. Sherman, All Rights Reserved.            */
/*   In particular, the right to republish this file in whole or in    */        /*   In particular, the right to republish this file in whole or in    */
/*   part, in any form (including electronic forms) is prohibited      */        /*   part, in any form (including electronic forms) is prohibited      */
/*   without written consent of the copyright holder.                  */        /*   without written consent of the copyright holder.                  */
/***********************************************************************/        /***********************************************************************/
#include <stdio.h>      /* needed for printf(), etc. */                          #include <stdio.h>      /* needed for printf(), etc. */
#include <stdlib.h>     /* needed for exit() */                                  #include <stdlib.h>     /* needed for exit() & getenv() */
#include <signal.h>     /* needed for signal() and its arguments */              #include <signal.h>     /* needed for signal() and its arguments */
#include <unistd.h>     /* not sure why/whether this is needed */                #include <unistd.h>     /* not sure why/whether this is needed */
#include <math.h>       /* needed for fabs() */                                  #include <math.h>       /* needed for fabs() */
 
#include <GL/gl.h>      /* needed for all OpenGL functions & values */           #include <GL/gl.h>      /* needed for all OpenGL functions & values */
 
#include "freevr.h"     /* needed for FreeVR functions & values */               #include "freevr.h"     /* needed for FreeVR functions & values */
#define WAND_SENSOR     1       /* TODO: this should really be based on the c    #define WAND_SENSOR     1       /* TODO: this should really be based on the c
 
                                                                                 /* Define some values to adjust the compilation of this example */
                                                                                 #define MAX_OBJECTS     4
                                                                                
 
/* Define a structure for information about each individual object. */           /* Define a structure for information about each individual object. */
typedef struct {                                                                 typedef struct {
                float                           x, y, z;        /* location o                    float                   x, y, z;                /* location o
                GLubyte                         color[3];       /* color of t                    GLubyte                 color[3];               /* color of t
                enum { cube,pyramid,ud_pyramid }shape;          /* shape of t                    enum {  cube,
                                                                                                         pyramid,
                                                                                                         ud_pyramid }    shape;                  /* shape of t
        } ObjectType;                                                                    } ObjectType;
 
/* Define a structure for holding a database of the virtual world. */            /* Define a structure for holding a database of the virtual world. */
typedef struct {                                                                 typedef struct {
                                                                                                 int             quit_bit;                       /* a flag to 
                int             number_of_objects;              /* number of                     int             number_of_objects;              /* number of 
                int             selected_object;                /* currently                     int             selected_object;                /* currently 
                ObjectType      object[3];                      /* array of o                    ObjectType      object[MAX_OBJECTS];            /* array of o
                vrLock          lock;                           /* to avoid b                    vrLock          lock;                           /* to avoid b
        } WorldDataType;                                                                 } WorldDataType;
 
 
/****************************************************************************    /****************************************************************************
/* These function declarations are very important -- they will be used as arg    /* These function declarations are very important -- they will be used as arg
void    exit_application(int signal);           /* cleanly close down operati    void    exit_application(int signal);           /* cleanly close down operati
 
void    init_gfx(void);                         /* initialize the graphics       void    init_gfx();                             /* initialize the graphics   
void    draw_world(WorldDataType *wd, vrRenderInfo *rendinfo); /* render the     void    draw_world(WorldDataType *wd, vrRenderInfo *rendinfo); /* render the 
void    init_world(WorldDataType *wd);          /* initialize the world param    void    init_world(WorldDataType *wd);          /* initialize the world param
void    update_world(WorldDataType *wd);        /* perform the world simulati    void    update_world(WorldDataType *wd);        /* perform the world simulati
                                                                                
                                                                                 void    end_world();                            /* close down the world opera
                                                                                 void    init_objects(WorldDataType *wd);        /* initalize the objects in t
 
 
/***********************************************************************/        /***********************************************************************/
main(int argc, char* argv[])                                                     main(int argc, char* argv[])
{                                                                                {
        WorldDataType   *wd;                                                             WorldDataType   *wd;
 
        /**********************************/                                             /**********************************/
        /*** initialize FreeVR routines ***/                                             /*** initialize FreeVR routines ***/
        /**********************************/                                             /**********************************/
        signal(SIGINT, SIG_IGN);                                                         signal(SIGINT, SIG_IGN);
        vrConfigure(&argc, argv, NULL);         /* allow CLAs to affect confi            vrConfigure(&argc, argv, NULL);         /* allow CLAs to affect confi
        vrStart();                                                                       vrStart();
        signal(SIGINT, exit_application);                                                signal(SIGINT, exit_application);
 
        /********************/                                                           /********************/
        /* create the world */                                                           /* create the world */
        wd = (WorldDataType *)vrShmemAlloc0(sizeof(WorldDataType));                      wd = (WorldDataType *)vrShmemAlloc0(sizeof(WorldDataType));
        wd->lock = vrLockCreate();                                                       wd->lock = vrLockCreate();
        init_world(wd);                                                                  init_world(wd);
 
        /***************************************/                                        /***************************************/
        /* set up the FreeVR library functions */                                        /* set up the FreeVR library functions */
        vrFunctionSetCallback(VRFUNC_DISPLAY_INIT, vrCallbackCreate(init_gfx,            vrFunctionSetCallback(VRFUNC_DISPLAY_INIT, vrCallbackCreate(init_gfx,
        vrFunctionSetCallback(VRFUNC_DISPLAY, vrCallbackCreate(draw_world, 1,            vrFunctionSetCallback(VRFUNC_DISPLAY, vrCallbackCreate(draw_world, 1,
 
        /********************************************************/                       /********************************************************/
        /* define the application name, authors, controls, etc. */                       /* define the application name, authors, controls, etc. */
        vrSystemSetName("example 12 -- travel");                                         vrSystemSetName("example 13 -- socket");
        vrSystemSetAuthors("Bill Sherman");                                              vrSystemSetAuthors("Bill Sherman");
        vrSystemSetExtraInfo("An example to demonstrate traveling relative to            vrSystemSetExtraInfo("An example to demonstrate communicating with th
        vrSystemSetStatusDescription("Application running fine");                        vrSystemSetStatusDescription("Application running fine");
        vrInputSet2switchDescription(0, "Terminate the application");                    vrInputSet2switchDescription(0, "Terminate the application");
        vrInputSet2switchDescription(1, "Move the selected object");                     vrInputSet2switchDescription(1, "Move the selected object");
        vrInputSet2switchDescription(3, "Reset the travel matrix (take us hom            vrInputSet2switchDescription(3, "Reset the travel matrix (take us hom
        vrInputSetValuatorDescription(0, "Rotate us in the world about the Y-            vrInputSetValuatorDescription(0, "Rotate us in the world about the Y-
        vrInputSetValuatorDescription(1, "Move us though the world in the dir            vrInputSetValuatorDescription(1, "Move us though the world in the dir
        vrInputSet6sensorDescription(WAND_SENSOR, "Move a short cyan pointer             vrInputSet6sensorDescription(WAND_SENSOR, "Move a short cyan pointer 
 
        /***************************/                                                    /***************************/
        /*** do world simulation ***/                                                    /*** do world simulation ***/
        /***************************/                                                    /***************************/
        vrUserTravelReset(VR_ALLUSERS);                                                  vrUserTravelReset(VR_ALLUSERS);
        /* run until terminate key is pressed (Escape by default) */                     /* run until the user has indicated it's time not to */
        while(!vrGet2switchValue(0)) {                                                   while(!wd->quit_bit) {
                vrFrame();                                                                       vrFrame();
                update_world(wd);                                                                update_world(wd);
        }                                                                                }
 
        /*********************/                                                          /*********************/
        /*** close up shop ***/                                                          /*** close up shop ***/
        /*********************/                                                          /*********************/
        exit_application(0);                                                             exit_application(0);
}                                                                                }
 
 
/********************************************************************/           /********************************************************************/
/* exit_application(): clean up anything started by the application */           /* exit_application(): clean up anything started by the application */
/*   (forked processes, open files, open sockets, etc.)             */           /*   (forked processes, open files, open sockets, etc.)             */
/********************************************************************/           /********************************************************************/
void exit_application(int signal)                                                void exit_application(int signal)
{                                                                                {
                                                                                         end_world();
                                                                                
        vrExit();                                                                        vrExit();
 
        exit(0);                                                                         exit(0);
}                                                                                }
 
 
 
/* ----------------8<-----------------8<-----------------8<----------------*/    /* ----------------8<-----------------8<-----------------8<----------------*/
/* In a non-example applicatation, the following would be a separate file. */    /* In a non-example applicatation, the following would be a separate file. */
 
                /**********************************/                                             /**********************************/
                /**********************************/                                             /**********************************/
                /** The World Simulation section **/                                             /** The World Simulation section **/
                /**********************************/                                             /**********************************/
                /**********************************/                                             /**********************************/
 
                                                                                 static int      listen_sock = -1;       /* socket to receive commands */
                                                                                                                         /*   listen_sock is not in wd        
                                                                                                                         /*   because it needs to be          
                                                                                                                         /*   available to exit_application() 
                                                                                                                         /*   which can have no arguments.    
 
/**************************************************************/                
/* init_world(): create the initial conditions of the dynamic */                 /****************************************************************/
/*   simulation.                                              */                 /* init_world(): create the initial conditions of the dynamic   */
/**************************************************************/                 /*   simulation.  Now with the addition of code to initialize a */
                                                                                 /*   socket communication interface.                            */
                                                                                 /*                                                              */
                                                                                 /*   The socket server port to be used can be set from the      */
                                                                                 /*   "VR_PORT" environment variable.  If it is set, then its    */
                                                                                 /*   value is used as the initial server socket port.           */
                                                                                 /*   Otherwise, the arbitrarily chosen port number 4000 is used.*/
                                                                                 /*                                                              */
                                                                                 /*   Since IRIX, and perhaps other Unicies have a "feature" in  */
                                                                                 /*   which a socket port isn't usable again until after 60      */
                                                                                 /*   seconds have passed since the connection was closed, if the*/
                                                                                 /*   initial socket isn't available, we try the next two ports  */
                                                                                 /*   in succession.  The selected port is reported to the tty.  */
                                                                                 /****************************************************************/
void init_world(WorldDataType *wd)                                               void init_world(WorldDataType *wd)
{                                                                                {
                                                                                         int     inet_port;
                                                                                         int     inet_port_max;
                                                                                         char    host_machine[128];
                                                                                
                                                                                         /*************************/
                                                                                         /* set world state flags */
                                                                                         vrLockWriteSet(wd->lock);
                                                                                         wd->quit_bit = 0;
                                                                                         vrLockWriteRelease(wd->lock);
                                                                                
                                                                                         /***************************/
                                                                                         /* setup the world content */
                                                                                         init_objects(wd);
                                                                                
                                                                                         /******************************/
                                                                                         /* initialize the socket port */
                                                                                         gethostname(host_machine, 128);
                                                                                
                                                                                         /* loop through N possible internet ports to hopefully find one that 
                                                                                         if (getenv("VR_PORT") != NULL)
                                                                                                 inet_port = atoi(getenv("VR_PORT"));
                                                                                         else    inet_port = 4000;
                                                                                         for (inet_port_max = inet_port + 2; listen_sock < 0 && inet_port <= i
                                                                                                 printf("Port %d -- ", inet_port);
                                                                                                 fflush(stdout);
                                                                                                 listen_sock = vrSocketCreateListen(&inet_port, 0);
                                                                                         }
                                                                                         inet_port--;
                                                                                         if (listen_sock < 0)
                                                                                                 printf("WARNING: Unable to find an open socket port.\n");
                                                                                         else    printf("\rConnect to '%s:%d' to send commands to the simulati
                                                                                 }
                                                                                
                                                                                
                                                                                 /***************************************************************/
                                                                                 /* init_objects(): place objects into the world data structure */
                                                                                 /*   at some initial positions.                                */
                                                                                 /***************************************************************/
                                                                                 void init_objects(WorldDataType *wd)
                                                                                 {
        int     objnum = 0;                                                              int     objnum = 0;
 
        vrLockWriteSet(wd->lock);                                                        vrLockWriteSet(wd->lock);
 
        /* object 1 - a blue cube */                                                     /* object 1 - a blue cube */
        wd->object[objnum].shape = cube;                                                 wd->object[objnum].shape = cube;
        wd->object[objnum].color[0] = 100;                                               wd->object[objnum].color[0] = 100;
        wd->object[objnum].color[1] = 100;                                               wd->object[objnum].color[1] = 100;
        wd->object[objnum].color[2] = 255;                                               wd->object[objnum].color[2] = 255;
        wd->object[objnum].x =  0.0;                                                     wd->object[objnum].x =  0.0;
        wd->object[objnum].y =  5.0;                                                     wd->object[objnum].y =  5.0;
        wd->object[objnum].z = -4.0;                                                     wd->object[objnum].z = -4.0;
        objnum++;                                                                        objnum++;
 
        /* object 2 - a red pyramid */                                                   /* object 2 - a red pyramid */
        wd->object[objnum].shape = pyramid;                                              wd->object[objnum].shape = pyramid;
        wd->object[objnum].color[0] = 255;                                               wd->object[objnum].color[0] = 255;
        wd->object[objnum].color[1] = 100;                                               wd->object[objnum].color[1] = 100;
        wd->object[objnum].color[2] = 100;                                               wd->object[objnum].color[2] = 100;
        wd->object[objnum].x = -4.0;                                                     wd->object[objnum].x = -4.0;
        wd->object[objnum].y =  5.0;                                                     wd->object[objnum].y =  5.0;
        wd->object[objnum].z = -4.0;                                                     wd->object[objnum].z = -4.0;
        objnum++;                                                                        objnum++;
 
        /* object 3 - an upside-down green pyramid */                                    /* object 3 - an upside-down green pyramid */
        wd->object[objnum].shape = ud_pyramid;                                           wd->object[objnum].shape = ud_pyramid;
        wd->object[objnum].color[0] = 100;                                               wd->object[objnum].color[0] = 100;
        wd->object[objnum].color[1] = 255;                                               wd->object[objnum].color[1] = 255;
        wd->object[objnum].color[2] = 100;                                               wd->object[objnum].color[2] = 100;
        wd->object[objnum].x =  4.0;                                                     wd->object[objnum].x =  4.0;
        wd->object[objnum].y =  5.0;                                                     wd->object[objnum].y =  5.0;
        wd->object[objnum].z = -4.0;                                                     wd->object[objnum].z = -4.0;
        objnum++;                                                                        objnum++;
 
        wd->number_of_objects = objnum;                                                  wd->number_of_objects = objnum;
        wd->selected_object = -1;                                                        wd->selected_object = -1;
 
                                                                                         /* sanity test */
                                                                                         if (objnum > MAX_OBJECTS) {
                                                                                                 printf("DANGER: Number of objects (%d), exceeds maximum allow
                                                                                         }
                                                                                
        vrLockWriteRelease(wd->lock);                                                    vrLockWriteRelease(wd->lock);
}                                                                                }
 
 
                                                                                 /*******************************************************/
                                                                                 /* end_world(): clean up anything opened by simulation */
                                                                                 /*******************************************************/
                                                                                 void end_world()
                                                                                 {
                                                                                         vrSocketClose(listen_sock);
                                                                                 }
                                                                                
                                                                                
/*********************************************************************/          /*********************************************************************/
/* update_world(): In this version, we handle the user interactions. */          /* update_world(): In this version, we handle the user interactions. */
/*   Both selecting, and moving the selected object.                 */          /*   Both selecting, and moving the selected object.                 */
/*********************************************************************/          /*********************************************************************/
void update_world(WorldDataType *wd)                                             void update_world(WorldDataType *wd)
{                                                                                {
#define JS_EPSILON      0.125                           /* the dead-zone befo    #define JS_EPSILON      0.125                           /* the dead-zone befo
#define MOVE_FACTOR     2.5                             /* a scale factor to     #define MOVE_FACTOR     2.5                             /* a scale factor to 
#define TURN_FACTOR     25.0                            /* a scale factor to     #define TURN_FACTOR     25.0                            /* a scale factor to 
#define SUB_JS_EPSILON(a)       ((a)-copysign(JS_EPSILON,(a)))  /* a macro to    #define SUB_JS_EPSILON(a)       ((a)-copysign(JS_EPSILON,(a)))  /* a macro to
                                                                                 static  char    *help_msg = "Socket commands:\n"
                                                                                                                 "\thelp -- this message\n"
                                                                                                                 "\tquit -- quit the application\n"
                                                                                                                 "\tclose -- close the connection\n"
                                                                                                                 "\treset -- reset the application\n"
                                                                                                                 "\tmove cube up -- translate the cube up 2 fe
                                                                                                                 "\tmove cube down -- translate the cube down 
                                                                                                                 "\twhere -- report the user's position in the
                                                                                                                 "\twhere am i -- report the user's position i
                                                                                                                 "\tshow ActiveWalls -- report some CAVE confi
                                                                                                 "";
                                                                                 static  int     cmd_socket = -1;        /* socket to get commands from */
                                                                                 static  char    buf[128];               /* socket read buffer          */
                                                                                 static  char    msg[128];               /* socket send buffer          */
                                                                                         int     result;                 /* result of reading a socket  */
                                                                                
static  vrTime          last_time = -1.0;               /* initially set to a    static  vrTime          last_time = -1.0;               /* initially set to a
        vrTime          sim_time = vrCurrentSimTime();  /* the current time o            vrTime          sim_time = vrCurrentSimTime();  /* the current time o
static  vrPoint         last_wand_vw_locpnt;            /* VW location of the    static  vrPoint         last_wand_vw_locpnt;            /* VW location of the
        vrPoint         wand_vw_locpnt;                 /* current location o            vrPoint         wand_vw_locpnt;                 /* current location o
#define last_wand_vw_loc last_wand_vw_locpnt.v                                   #define last_wand_vw_loc last_wand_vw_locpnt.v
#define wand_vw_location wand_vw_locpnt.v                                        #define wand_vw_location wand_vw_locpnt.v
        vrVector        wand_rw_pointvec;               /* current vector poi            vrVector        wand_rw_pointvec;               /* current vector poi
        double          delta_time;                     /* time since last up            double          delta_time;                     /* time since last up
        double          delta_move;                     /* distance an object            double          delta_move;                     /* distance an object
        double          joy_x, joy_y;                   /* Joystick values */            double          joy_x, joy_y;                   /* Joystick values */
        int             selected_obj;                   /* the currently sele            int             selected_obj;                   /* the currently sele
        int             touch_obj = -1;                 /* the currently touc            int             touch_obj = -1;                 /* the currently touc
        int             objnum;                         /* for looping throuh            int             objnum;                         /* for looping throuh
        ObjectType      *object;                        /* pointer to object             ObjectType      *object;                        /* pointer to object 
 
        /*****************************************************/                          /*****************************************************/
        /** Determine delta time from last simulation frame **/                          /** Determine delta time from last simulation frame **/
        /*****************************************************/                          /*****************************************************/
        if (last_time == -1.0)                                                           if (last_time == -1.0)
                delta_time = 0.0;                                                                delta_time = 0.0;
        else    delta_time = sim_time - last_time;                                       else    delta_time = sim_time - last_time;
        last_time = sim_time;                           /* now that delta_tim            last_time = sim_time;                           /* now that delta_tim
 
        /* skip the update if the delta isn't big enough */                              /* skip the update if the delta isn't big enough */
        if (delta_time <= 0.0)  /* can also choose a non-zero epsilon */                 if (delta_time <= 0.0)  /* can also choose a non-zero epsilon */
                return;                                                                          return;
 
        /**********************************/                                             /**********************************/
        /** Handle Manipulation via wand **/                                             /** Handle Manipulation via wand **/
        /**********************************/                                             /**********************************/
 
        /**********************************************************/                     /**********************************************************/
        /* check for contact between the wand and all the objects */                     /* check for contact between the wand and all the objects */
        /* Note, this is very course locking.  We could also lock just */     
        /*   around the lines that actually access the world database. */     
        vrLockReadSet(wd->lock);                                                         vrLockReadSet(wd->lock);
 
        vrPointGetVWFromUser6sensor(&wand_vw_locpnt, 0, WAND_SENSOR);                    vrPointGetVWFromUser6sensor(&wand_vw_locpnt, 0, WAND_SENSOR);
 
        for (objnum = 0; objnum < wd->number_of_objects; objnum++) {                     for (objnum = 0; objnum < wd->number_of_objects; objnum++) {
                if ( (wand_vw_location[VR_X] < wd->object[objnum].x + 1.0)                       object = &(wd->object[objnum]);
                  && (wand_vw_location[VR_X] > wd->object[objnum].x - 1.0)                       if ( (wand_vw_location[VR_X] < object->x + 1.0)
                  && (wand_vw_location[VR_Y] < wd->object[objnum].y + 1.0)                         && (wand_vw_location[VR_X] > object->x - 1.0)
                  && (wand_vw_location[VR_Y] > wd->object[objnum].y - 1.0)                         && (wand_vw_location[VR_Y] < object->y + 1.0)
                  && (wand_vw_location[VR_Z] < wd->object[objnum].z + 1.0)                         && (wand_vw_location[VR_Y] > object->y - 1.0)
                  && (wand_vw_location[VR_Z] > wd->object[objnum].z - 1.0) )                       && (wand_vw_location[VR_Z] < object->z + 1.0)
                                                                                                   && (wand_vw_location[VR_Z] > object->z - 1.0) ) {
                        touch_obj = objnum;                                                              touch_obj = objnum;
                }                                                                                }
        }                                                                                }
 
        selected_obj = wd->selected_object;                                              selected_obj = wd->selected_object;
 
        vrLockReadRelease(wd->lock);                                                     vrLockReadRelease(wd->lock);
 
        if (selected_obj != touch_obj) {                                                 if (selected_obj != touch_obj) {
                /* NOTE: a local variable (touch_obj) is used because it */                      /* NOTE: a local variable (touch_obj) is used because it */
                /*   decreases the time the lock must be held.           */                      /*   decreases the time the lock must be held.           */
                vrLockWriteSet(wd->lock);                                                        vrLockWriteSet(wd->lock);
                wd->selected_object = touch_obj;                                                 wd->selected_object = touch_obj;
                vrLockWriteRelease(wd->lock);                                                    vrLockWriteRelease(wd->lock);
 
                selected_obj = touch_obj;                                                        selected_obj = touch_obj;
        }                                                                                }
 
        /* when left wand button is pressed, the selected object is moved */             /* when left wand button is pressed, the selected object is moved */
        if (vrGet2switchValue(1) && (selected_obj != -1)) {                              if (vrGet2switchValue(1) && (selected_obj != -1)) {
                vrLockWriteSet(wd->lock);                                                        vrLockWriteSet(wd->lock);
                object = &(wd->object[selected_obj]);                                            object = &(wd->object[selected_obj]);
                object->x += (wand_vw_location[VR_X] - last_wand_vw_loc[VR_X]                    object->x += (wand_vw_location[VR_X] - last_wand_vw_loc[VR_X]
                object->y += (wand_vw_location[VR_Y] - last_wand_vw_loc[VR_Y]                    object->y += (wand_vw_location[VR_Y] - last_wand_vw_loc[VR_Y]
                object->z += (wand_vw_location[VR_Z] - last_wand_vw_loc[VR_Z]                    object->z += (wand_vw_location[VR_Z] - last_wand_vw_loc[VR_Z]
                vrLockWriteRelease(wd->lock);                                                    vrLockWriteRelease(wd->lock);
        }                                                                                }
 
        /******************************************************************/             /******************************************************************/
        /* store the current wand location for next time through the loop */             /* store the current wand location for next time through the loop */
        last_wand_vw_loc[VR_X] = wand_vw_location[VR_X];                                 last_wand_vw_loc[VR_X] = wand_vw_location[VR_X];
        last_wand_vw_loc[VR_Y] = wand_vw_location[VR_Y];                                 last_wand_vw_loc[VR_Y] = wand_vw_location[VR_Y];
        last_wand_vw_loc[VR_Z] = wand_vw_location[VR_Z];                                 last_wand_vw_loc[VR_Z] = wand_vw_location[VR_Z];
 
 
   /**** begin new code from example 11 ****/                                 
        /****************************/                                                   /****************************/
        /** Handle Travel via wand **/                                                   /** Handle Travel via wand **/
        /****************************/                                                   /****************************/
 
        /* pressing the right wand button resets us to the initial position *            /* pressing the right wand button resets us to the initial position *
        if (vrGet2switchValue(3)) {                                                      if (vrGet2switchValue(3)) {
                vrUserTravelReset(VR_ALLUSERS);                                                  vrUserTravelReset(VR_ALLUSERS);
        }                                                                                }
 
        /* use wand joystick to fly through world */                                     /* use wand joystick to fly through world */
        joy_x = vrGetValuatorValue(0);                                                   joy_x = vrGetValuatorValue(0);
        joy_y = vrGetValuatorValue(1);                                                   joy_y = vrGetValuatorValue(1);
 
        if (fabs(joy_x) > JS_EPSILON)                                                    if (fabs(joy_x) > JS_EPSILON)
                vrUserTravelRotateId(VR_ALLUSERS, VR_Y, (delta_time * SUB_JS_                    vrUserTravelRotateId(VR_ALLUSERS, VR_Y, (delta_time * SUB_JS_
 
        if (fabs(joy_y) > JS_EPSILON) {                                                  if (fabs(joy_y) > JS_EPSILON) {
                delta_move = delta_time * SUB_JS_EPSILON(joy_y) * MOVE_FACTOR                    delta_move = delta_time * SUB_JS_EPSILON(joy_y) * MOVE_FACTOR
                vrVectorGetRWFrom6sensorDir(&wand_rw_pointvec, WAND_SENSOR, V                    vrVectorGetRWFrom6sensorDir(&wand_rw_pointvec, WAND_SENSOR, V
                vrUserTravelTranslate3d(VR_ALLUSERS,                                             vrUserTravelTranslate3d(VR_ALLUSERS,
                        wand_rw_pointvec.v[VR_X] * delta_move,                                           wand_rw_pointvec.v[VR_X] * delta_move,
                        wand_rw_pointvec.v[VR_Y] * delta_move,                                           wand_rw_pointvec.v[VR_Y] * delta_move,
                        wand_rw_pointvec.v[VR_Z] * delta_move);                                          wand_rw_pointvec.v[VR_Z] * delta_move);
        }                                                                                }
   /**** end new code ****/                                                     
                                                                                
                                                                                         /*******************************/
                                                                                         /* Handle Commands from socket */
                                                                                
                                                                                         /* if no connection (and a listen socket is open), see if someone is 
                                                                                         if (cmd_socket < 0 && listen_sock >= 0) {
                                                                                                 /* cmd_socket will be -1 when no one is connected */
                                                                                                 cmd_socket = vrSocketAnswer(listen_sock);
                                                                                                 if (cmd_socket > 0) {
                                                                                                         printf("New client connected.\n");
                                                                                                         vrSocketSendMsg(cmd_socket, "Your wish is my command 
                                                                                                 }
                                                                                         }
                                                                                
                                                                                         /* if a connection, see if client sent a command.  If so, act on it *
                                                                                         if (cmd_socket > 0) {
                                                                                                 result = vrSocketReadMsgClean(cmd_socket, buf, 128);
                                                                                                 switch (result) {
                                                                                                 case -1:
                                                                                                         break;
                                                                                                 case  0:
                                                                                                         printf("Client stopped communicating.\n");
                                                                                                         close(cmd_socket);
                                                                                                         cmd_socket = -1;
                                                                                                         break;
                                                                                                 default:
                                                                                                         printf("socket cmd = '%s'\n", buf);
                                                                                                         /* parse command here -- very simple-minded parsing *
                                                                                                         if (strcmp(buf, "quit") == 0) {
                                                                                                                 /* set the world for termination */
                                                                                                                 wd->quit_bit = 1;
                                                                                                         } else
                                                                                                         if (strcmp(buf, "help") == 0 || strcmp(buf, "?") == 0
                                                                                                                 /* give usage information */
                                                                                                                 vrSocketSendMsg(cmd_socket, help_msg);
                                                                                                         } else
                                                                                                         if (strcmp(buf, "close") == 0) {
                                                                                                                 /* close socket connection */
                                                                                                                 printf("Client ending communication.\n");
                                                                                                                 close(cmd_socket);
                                                                                                                 cmd_socket = -1;
                                                                                                         } else
                                                                                                         if (strcmp(buf, "reset") == 0) {
                                                                                                                 /* make the world as it was in the beginning 
                                                                                                                 init_objects(wd);
                                                                                                                 vrUserTravelReset(VR_ALLUSERS);
                                                                                                         } else
                                                                                                         if (strcmp(buf, "move cube up") == 0) {
                                                                                                                 /* move the blue cube up 2.0 units */
                                                                                                                 wd->object[0].y += 2.0;
                                                                                                         } else
                                                                                                         if (strcmp(buf, "move cube down") == 0) {
                                                                                                                 /* move the blue cube down 2.0 units */
                                                                                                                 wd->object[0].y -= 2.0;
                                                                                                         } else
                                                                                                         if (strcmp(buf, "where") == 0 || strcmp(buf, "where a
                                                                                                                 /* report the user's location */
                                                                                                                 vrMatrix        *headmat;
                                                                                                                 vrPoint         headloc;
                                                                                
                                                                                                                 headmat = vrMatrixCreate();
                                                                                                                 vrMatrixGetRWFromUserHead(headmat, 0);
                                                                                                                 vrPointGetVWFromUserMatrix(&headloc, 0, headm
                                                                                                                 sprintf(msg, "You are at (%f %f %f).\n", head
                                                                                                                 vrSocketSendMsg(cmd_socket, msg);
                                                                                                         } else
                                                                                                         if (strcmp(buf, "show ActiveWalls") == 0) {
                                                                                                                 /* report the type of graphics (VR) display *
                                                                                                                 sprintf(msg, "Application has %d active walls
                                                                                                                 vrSocketSendMsg(cmd_socket, msg);
                                                                                                         } else
                                                                                                         /* default: */ {
                                                                                                                 vrSocketSendMsg(cmd_socket, "Unknown command.
                                                                                                         }
                                                                                
                                                                                                         /* prompt for another command (if socket still open) 
                                                                                                         if (cmd_socket > 0) {
                                                                                                                 vrSocketSendMsg(cmd_socket, "Your wish is my 
                                                                                                         }
                                                                                                 }
                                                                                         }
                                                                                
                                                                                         /*********************************/
                                                                                         /* Handle Commands from keyboard */
                                                                                         if (vrGet2switchValue(0)) {
                                                                                                 wd->quit_bit = 1;
                                                                                         }
 
        /****************************************************/                           /****************************************************/
        /* yield to allow other processes access to the CPU */                           /* yield to allow other processes access to the CPU */
        vrSleep(0);                                                                      vrSleep(0);
}                                                                                }
 
 
 
/* ----------------8<-----------------8<-----------------8<----------------*/    /* ----------------8<-----------------8<-----------------8<----------------*/
/* In a non-example applicatation, the following would be a separate file. */    /* In a non-example applicatation, the following would be a separate file. */
 
                /**************************/                                                     /**************************/
                /**************************/                                                     /**************************/
                /** The Graphics section **/                                                     /** The Graphics section **/
                /**************************/                                                     /**************************/
                /**************************/                                                     /**************************/
 
/* functions from shapes.c */                                                    /* functions from shapes.c */
void    draw_floor();                                                            void    draw_floor();
void    draw_cube();                                                             void    draw_cube();
void    draw_pyramid();                                                          void    draw_pyramid();
void    draw_cube_outline();                                                     void    draw_cube_outline();
void    draw_pyramid_outline();                                                  void    draw_pyramid_outline();
 
 
/*********************************************************************/          /*********************************************************************/
/* init_gfx(): initialize general graphics properties (eg. lighting) */          /* init_gfx(): initialize general graphics properties (eg. lighting) */
/*********************************************************************/          /*********************************************************************/
void init_gfx(void)                                                              void init_gfx()
{                                                                                {
        GLfloat location_0[4] = { 0.0, 10.0, 10.0, 1.0 /* 0 = directional, 1             GLfloat location_0[4] = { 0.0, 10.0, 10.0, 1.0 /* 0 = directional, 1 
                ambient_0[4] = { 0.2, 0.2, 0.2, 1.0 },                                           ambient_0[4] = { 0.2, 0.2, 0.2, 1.0 },
                diffuse_0[4] = { 0.8, 0.8, 0.8, 1.0 },                                           diffuse_0[4] = { 0.8, 0.8, 0.8, 1.0 },
                specular_0[4] = { 0.2, 0.2, 0.2, 1.0 };                                          specular_0[4] = { 0.2, 0.2, 0.2, 1.0 };
 
                                                                              
        /****************************************/                                       /****************************************/
        /* set the render initialization values */                                       /* set the render initialization values */
        glClearColor(0.0, 0.0, 0.0, 0.0);                                                glClearColor(0.0, 0.0, 0.0, 0.0);
        glClearDepth(1.0);                                                               glClearDepth(1.0);
 
        /********************************************************/                       /********************************************************/
        /* set the polygon shading/lighting/material parameters */                       /* set the polygon shading/lighting/material parameters */
        glShadeModel(GL_SMOOTH);                                                         glShadeModel(GL_SMOOTH);
 
        glEnable(GL_LIGHTING);                                                           glEnable(GL_LIGHTING);
 
        glLightfv(GL_LIGHT0, GL_POSITION, location_0);                                   glLightfv(GL_LIGHT0, GL_POSITION, location_0);
        glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_0);                                     glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_0);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_0);                                     glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_0);
        glLightfv(GL_LIGHT0, GL_SPECULAR, specular_0);                                   glLightfv(GL_LIGHT0, GL_SPECULAR, specular_0);
        glEnable(GL_LIGHT0);                                                             glEnable(GL_LIGHT0);
 
        /* These two lines cause the vertex colors to be used (otherwise all             /* These two lines cause the vertex colors to be used (otherwise all 
        glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);                               glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
        glEnable(GL_COLOR_MATERIAL);                                                     glEnable(GL_COLOR_MATERIAL);
 
        glEnable(GL_NORMALIZE); /* this is required when calling glScalef() w            glEnable(GL_NORMALIZE); /* this is required when calling glScalef() w
 
        /***************************/                                                    /***************************/
        /* set the line parameters */                                                    /* set the line parameters */
        glEnable(GL_LINE_SMOOTH);                                                        glEnable(GL_LINE_SMOOTH);
        glLineWidth(2.0);                                                                glLineWidth(2.0);
}                                                                                }
 
 
/*******************************************************************/            /*******************************************************************/
/* draw_world(): Now will render how ever many objects are in the  */            /* draw_world(): Now will render how ever many objects are in the  */
/*   world data structure.  The color, type (and maybe rotation)   */            /*   world data structure.  The color, type (and maybe rotation)   */
/*   are all now stored for each object, in addition to location.  */            /*   are all now stored for each object, in addition to location.  */
/*   The currently selected object is highlighted by adding a      */            /*   The currently selected object is highlighted by adding a      */
/*   wireframe outline to the representation.                      */            /*   wireframe outline to the representation.                      */
/*******************************************************************/            /*******************************************************************/
void draw_world(WorldDataType *wd, vrRenderInfo *rendinfo)                       void draw_world(WorldDataType *wd, vrRenderInfo *rendinfo)
{                                                                                {
static  GLfloat         location_0[4] = { 0.0, 10.0, 0.0, 1.0 /* 0 = directio    static  GLfloat         location_0[4] = { 0.0, 10.0, 0.0, 1.0 /* 0 = directio
static  char            msg[128];                       /* memory for text st    static  char            msg[128];                       /* memory for text st
        int             objnum;                         /* object counter */             int             objnum;                         /* object counter */
                                                                                         ObjectType      *object;                        /* pointer to current
 
        /**************************************/                                         /**************************************/
        /* clear the screen -- very important */                                         /* clear the screen -- very important */
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);                              glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
        /********************************************************************            /********************************************************************
        /* update the light's location -- must be done independently for each            /* update the light's location -- must be done independently for each
        glLightfv(GL_LIGHT0, GL_POSITION, location_0);                                   glLightfv(GL_LIGHT0, GL_POSITION, location_0);
 
        /************************************/                                           /************************************/
        /* draw a short pointer at the wand */                                           /* draw a short pointer at the wand */
        glPushMatrix();                                                                  glPushMatrix();
                glColor3ub(100, 255, 255);      /* cyan */                                       glColor3ub(100, 255, 255);      /* cyan */
                vrRenderTransform6sensor(rendinfo, WAND_SENSOR);                                 vrRenderTransform6sensor(rendinfo, WAND_SENSOR);
                glRotatef(-90.0, 1.0, 0.0, 0.0);                                                 glRotatef(-90.0, 1.0, 0.0, 0.0);
                glScalef(0.15, 0.15, 0.15);                                                      glScalef(0.15, 0.15, 0.15);
                glTranslatef(0.0, 1.5, 0.0);                                                     glTranslatef(0.0, 1.5, 0.0);
                draw_pyramid_outline();                                                          draw_pyramid_outline();
        glPopMatrix();                                                                   glPopMatrix();
 
        /*******************************************************/                        /*******************************************************/
        /* draw an object that remains fixed in physical space */                        /* draw an object that remains fixed in physical space */
        glColor3ub(200, 100, 255);      /* purple */                                     glColor3ub(200, 100, 255);      /* purple */
        glPushMatrix();                                                                  glPushMatrix();
                glTranslatef(-4.0, 1.0, -1.0);                                                   glTranslatef(-4.0, 1.0, -1.0);
                draw_cube();                                                                     draw_cube();
        glPopMatrix();                                                                   glPopMatrix();
 
        /******************************************************************/             /******************************************************************/
        /* draw the rest of the objects in virtual (user navigated) space */             /* draw the rest of the objects in virtual (user navigated) space */
        glPushMatrix();         /* save the real-world coordinate system */              glPushMatrix();         /* save the real-world coordinate system */
        vrRenderTransformUserTravel(rendinfo);                                           vrRenderTransformUserTravel(rendinfo);  /* change to virtual-world co
 
        draw_floor();                                                                    draw_floor();
 
        /* Note again, this is very course locking. */                                   vrLockReadSet(wd->lock);        /* lock while reading info about obje
        vrLockReadSet(wd->lock);                                              
        for (objnum = 0; objnum < wd->number_of_objects; objnum++) {                     for (objnum = 0; objnum < wd->number_of_objects; objnum++) {
                                                                                                 object = &(wd->object[objnum]);
 
                glColor3ubv(wd->object[objnum].color);                                           glColor3ubv(object->color);
                glPushMatrix();                                                                  glPushMatrix();
                        glTranslatef(wd->object[objnum].x, wd->object[objnum]                            glTranslatef(object->x, object->y, object->z);
                        switch (wd->object[objnum].shape) {                                              switch (object->shape) {
                        case cube:                                                                       case cube:
                                if (objnum == wd->selected_object)                                               if (objnum == wd->selected_object)
                                        draw_cube_outline();                                                             draw_cube_outline();
                                else    draw_cube();                                                             else    draw_cube();
                                break;                                                                           break;
                        case pyramid:                                                                    case pyramid:
                                if (objnum == wd->selected_object)                                               if (objnum == wd->selected_object)
                                        draw_pyramid_outline();                                                          draw_pyramid_outline();
                                else    draw_pyramid();                                                          else    draw_pyramid();
                                break;                                                                           break;
                        case ud_pyramid:                                                                 case ud_pyramid:
                                glScalef(1.0, -1.0, 1.0);                                                        glScalef(1.0, -1.0, 1.0);
                                if (objnum == wd->selected_object)                                               if (objnum == wd->selected_object)
                                        draw_pyramid_outline();                                                          draw_pyramid_outline();
                                else    draw_pyramid();                                                          else    draw_pyramid();
                                break;                                                                           break;
                        }                                                                                }
                glPopMatrix();                                                                   glPopMatrix();
        }                                                                                }
 
        glPopMatrix();  /* return to real-world coordinates */                           glPopMatrix();  /* return to real-world coordinates */
        /* NOTE: 2-D text is best rendered in a fixed location in the world *            /* NOTE: 2-D text is best rendered in a fixed location in the world *
 
        /*************************************************/                              /*************************************************/
        /* draw text indicating which object is selected */                              /* draw text indicating which object is selected */
        if (wd->selected_object < 0) {                                                   if (wd->selected_object < 0) {
                sprintf(msg, "Object selected: none");                                           sprintf(msg, "Object selected: none");
        } else {                                                                         } else {
                sprintf(msg, "Object selected: %d", wd->selected_object);                        sprintf(msg, "Object selected: %d", wd->selected_object);
        }                                                                                }
 
        vrLockReadRelease(wd->lock);                                                     vrLockReadRelease(wd->lock);
 
        glDisable(GL_LIGHTING);         /* make the text bright regardless of            glDisable(GL_LIGHTING);         /* make the text bright regardless of
        glColor3ub(255, 255, 255);      /* white */                                      glColor3ub(255, 255, 255);      /* white */
        glPushMatrix();                                                                  glPushMatrix();
                glTranslatef(-4.0, 7.0, -5.0);  /* on the front screen */                        glTranslatef(-4.0, 7.0, -5.0);  /* on the front screen */
 
                glRasterPos3f(0.0, 0.0, 0.0);   /* go to the 3D location */                      glRasterPos3f(0.0, 0.0, 0.0);   /* go to the 3D location */
                vrRenderText(rendinfo, msg);                                                     vrRenderText(rendinfo, msg);
        glPopMatrix();                                                                   glPopMatrix();
        glEnable(GL_LIGHTING);                                                           glEnable(GL_LIGHTING);
}                                                                                }