/***********************************************************************/ /***********************************************************************/ /* FreeVR OpenGL tutorial example 18: ex18_billboard.c */ /* FreeVR OpenGL tutorial example 19: ex19_wim.c */ /* Last tested with: FreeVR version 0.6a */ /* Last tested with: FreeVR version 0.6a */ /* Last Modified: September 23, 2005 */ /* Last Modified: October 12, 2010 */ /* URL: http://freevr.org */ /* URL: http://freevr.org */ /***********************************************************************/ /***********************************************************************/ /* This example code demonstrates a VR application program that can */ /* This example code demonstrates a VR application program that can */ /* render objects to always face the participant. This can be done */ /* render a miniature version of the world, along with the full size */ /* just about the Y (up) axis -- cylidrical billboarding -- or about */ /* one. */ /* both the Y and the X (lateral) axis -- spherical billboarding. */ /* */ /* */ /* */ /* */ /* The new features of this example include: */ /* The new features of this example include: */ /* - vrRenderGetBillboardAngles3d() */ /* - the WIM is attached to the wand (replaces the wand's avatar) */ /* - (perhaps) vrEuler type */ /* A world-in-miniature is a handy exo-view wayfinding tool */ /* - pressing button 2 summons the WIM display */ /* - the rendering of the world is now a separate function (since */ /* now we have to render the world twice. */ /* - function vrRenderTransformUserTravelInv() is introduced. */ /* */ /* */ /* */ /* */ /* Considerations: */ /* Considerations: */ /* - Billboarding can either be cylindrical or spherical */ /* - need a difficult navigational space to make use of WIM -- maze */ /* - walk-through (vs. fly-through) travel also increases utility */ /* - adding a self-avatar to the WIM requires factoring *OUT* the */ /* travel, and factoring IN the physical locomotion. */ /* */ /* */ /* This application uses the files: */ /* This application uses the files: */ /* - wrs_shapes.c (Bill Sherman's simple OpenGL shapes) */ /* - wrs_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() & getenv() */ #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 <inttypes.h> /* needed for "uint32_t" type */ #include <inttypes.h> /* needed for "uint32_t" type */ #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 HEAD_SENSOR 0 #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 some values to adjust the compilation of this example */ #define USE_SOCKETS #define USE_SOCKETS #define MAX_OBJECTS 5 #define MAX_OBJECTS 40 #define NO_TEXT 0 #define NO_TEXT 0 #define X_2DTEXT 1 #define X_2DTEXT 1 #define GLUT_2DTEXT 2 #define GLUT_2DTEXT 2 #define GLUT_3DTEXT 3 #define GLUT_3DTEXT 3 #define TEXT_STYLE X_2DTEXT #define TEXT_STYLE X_2DTEXT #if (TEXT_STYLE == GLUT_2DTEXT || TEXT_STYLE == GLUT_3DTEXT) #if (TEXT_STYLE == GLUT_2DTEXT || TEXT_STYLE == GLUT_3DTEXT) # include <GL/glut.h> /* needed for Glut functions -- primarily text render # include <GL/glut.h> /* needed for Glut functions -- primarily text render #endif #endif /* 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 float size; /* size of th float size; /* size of th GLubyte color[3]; /* color of t GLubyte color[3]; /* color of t GLuint texture_id; /* texture ID GLuint texture_id; /* texture ID char *msg; /* text of a char *msg; /* text of a enum { cube, enum { cube, tex_cube, tex_cube, tex_plane, tex_plane, sphere, sphere, pyramid, pyramid, ud_pyramid, ud_pyramid, billboard_c, billboard_s, text } shape; /* shape of t text } 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 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 int show_wim; /* flag indic ObjectType object[MAX_OBJECTS]; /* 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(); /* 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 end_world(); /* close down the world opera void init_objects(WorldDataType *wd); /* initalize the objects in t void init_objects(WorldDataType *wd); /* initalize the objects in t /***********************************************************************/ /***********************************************************************/ main(int argc, char* argv[]) main(int argc, char* argv[]) { { WorldDataType *wd; WorldDataType *wd; #ifdef FREEGLUT #ifdef FREEGLUT # if (TEXT_STYLE == GLUT_2DTEXT || TEXT_STYLE == GLUT_3DTEXT) # if (TEXT_STYLE == GLUT_2DTEXT || TEXT_STYLE == GLUT_3DTEXT) /* NOTE: The FreeGlut version of Glut introduced the unnecessary */ /* NOTE: The FreeGlut version of Glut introduced the unnecessary */ /* requirement of calling glutInit(), even when the only use */ /* requirement of calling glutInit(), even when the only use */ /* of the Glut library is for rendering objects, and not using */ /* of the Glut library is for rendering objects, and not using */ /* the windowing or input side of Glut. Hopefully, one day, */ /* the windowing or input side of Glut. Hopefully, one day, */ /* either the FreeGlut project will eliminate this odd */ /* either the FreeGlut project will eliminate this odd */ /* requirement, or Linux distributions will shift to a */ /* requirement, or Linux distributions will shift to a */ /* different Glut distribution. */ /* different Glut distribution. */ glutInit(&argc, argv); glutInit(&argc, argv); # endif # endif #endif #endif /**********************************/ /**********************************/ /*** initialize FreeVR routines ***/ /*** initialize FreeVR routines ***/ /**********************************/ /**********************************/ signal(SIGINT, SIG_IGN); signal(SIGINT, SIG_IGN); vrShmemInit(1024*1024*8); /* needed for multiple screen vrShmemInit(1024*1024*8); /* needed for multiple screen 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 18 -- rendering billboards example"); vrSystemSetName("example 19 -- rendering world-in-miniature example") vrSystemSetAuthors("Bill Sherman"); vrSystemSetAuthors("Bill Sherman"); vrSystemSetExtraInfo("An example to demonstrate how to render billboa vrSystemSetExtraInfo("An example of a WIM in VR"); 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(2, "Turn on the WIM display"); 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 the user has indicated it's time not to */ /* run until the user has indicated it's time not to */ while(!wd->quit_bit) { 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(); 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 **/ /**********************************/ /**********************************/ /**********************************/ /**********************************/ #ifdef USE_SOCKETS /* { */ #ifdef USE_SOCKETS /* { */ static int listen_sock = -1; /* socket to receive commands static int listen_sock = -1; /* socket to receive commands /* listen_sock is not in wd /* listen_sock is not in wd /* because it needs to be /* because it needs to be /* available to exit_applic /* available to exit_applic /* which can have no argume /* which can have no argume #endif /* } USE_SOCKETS */ #endif /* } USE_SOCKETS */ /****************************************************************/ /****************************************************************/ /* init_world(): create the initial conditions of the dynamic */ /* init_world(): create the initial conditions of the dynamic */ /* simulation. If the "VR_PORT" environment variable is set, */ /* simulation. If the "VR_PORT" environment variable is set, */ /* then its value is used as the initial server socket port. */ /* then its value is used as the initial server socket port. */ /* Otherwise, the arbitrarily chosen port number 4000 is used.*/ /* Otherwise, the arbitrarily chosen port number 4000 is used.*/ /* Since IRIX, and perhaps other Unicies have a "feature" in */ /* Since IRIX, and perhaps other Unicies have a "feature" in */ /* which a socket port isn't usable again until after 60 */ /* which a socket port isn't usable again until after 60 */ /* seconds have passed since the connection was closed, if the*/ /* seconds have passed since the connection was closed, if the*/ /* initial socket isn't available, we try the next two ports */ /* initial socket isn't available, we try the next two ports */ /* in succession. The selected port is reported to the tty. */ /* in succession. The selected port is reported to the tty. */ /****************************************************************/ /****************************************************************/ void init_world(WorldDataType *wd) void init_world(WorldDataType *wd) { { #ifdef USE_SOCKETS /* { */ #ifdef USE_SOCKETS /* { */ int inet_port; int inet_port; int inet_port_max; int inet_port_max; char host_machine[128]; char host_machine[128]; #endif /* } USE_SOCKETS */ #endif /* } USE_SOCKETS */ /*************************/ /*************************/ /* set world state flags */ /* set world state flags */ vrLockWriteSet(wd->lock); vrLockWriteSet(wd->lock); wd->quit_bit = 0; wd->quit_bit = 0; wd->show_wim = 0; vrLockWriteRelease(wd->lock); vrLockWriteRelease(wd->lock); /***************************/ /***************************/ /* setup the world content */ /* setup the world content */ init_objects(wd); init_objects(wd); #ifdef USE_SOCKETS /* { */ #ifdef USE_SOCKETS /* { */ /******************************/ /******************************/ /* initialize the socket port */ /* initialize the socket port */ gethostname(host_machine, 128); gethostname(host_machine, 128); /* loop through N possible internet ports to hopefully find one that /* loop through N possible internet ports to hopefully find one that if (getenv("VR_PORT") != NULL) if (getenv("VR_PORT") != NULL) inet_port = atoi(getenv("VR_PORT")); inet_port = atoi(getenv("VR_PORT")); else inet_port = 4000; else inet_port = 4000; for (inet_port_max = inet_port + 2; listen_sock < 0 && inet_port <= i for (inet_port_max = inet_port + 2; listen_sock < 0 && inet_port <= i printf("Port %d -- ", inet_port); printf("Port %d -- ", inet_port); fflush(stdout); fflush(stdout); listen_sock = vrSocketCreateListen(&inet_port, 0); listen_sock = vrSocketCreateListen(&inet_port, 0); } } inet_port--; inet_port--; if (listen_sock < 0) if (listen_sock < 0) printf("WARNING: Unable to find an open socket port.\n"); printf("WARNING: Unable to find an open socket port.\n"); else printf("\rConnect to '%s:%d' to send commands to the simulati else printf("\rConnect to '%s:%d' to send commands to the simulati #endif /* } USE_SOCKETS */ #endif /* } USE_SOCKETS */ } } /***************************************************************/ /***************************************************************/ /* init_objects(): place objects into the world data structure */ /* init_objects(): place objects into the world data structure */ /* at some initial positions. */ /* at some initial positions. */ /***************************************************************/ /***************************************************************/ void init_objects(WorldDataType *wd) void init_objects(WorldDataType *wd) { { int objnum = 0; int objnum = 0; vrLockWriteSet(wd->lock); vrLockWriteSet(wd->lock); #if 0 #if 0 /* object 1 - a blue cube */ /* object 1 - a blue cube */ wd->object[objnum].shape = cube; wd->object[objnum].shape = cube; wd->object[objnum].size = 1.0; wd->object[objnum].size = 1.0; 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++; #endif #endif /* object 2 - a red pyramid */ /* object 2 - a red pyramid */ wd->object[objnum].shape = pyramid; wd->object[objnum].shape = pyramid; wd->object[objnum].size = 1.0; wd->object[objnum].size = 1.0; 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 = -8.0; wd->object[objnum].x = -10.0; wd->object[objnum].y = 1.0; wd->object[objnum].y = 1.5; wd->object[objnum].z = -7.0; wd->object[objnum].z = -10.0; objnum++; objnum++; #if 0 #if 0 /* 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].size = 1.0; wd->object[objnum].size = 1.0; 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++; #endif #endif /* object 4 - some green text */ /* object 4 - some green text */ wd->object[objnum].shape = text; wd->object[objnum].shape = text; wd->object[objnum].size = 1.0; wd->object[objnum].size = 1.0; wd->object[objnum].color[0] = 255; wd->object[objnum].color[1] = 100; wd->object[objnum].color[2] = 100; wd->object[objnum].x = -10.0; wd->object[objnum].y = 2.5; wd->object[objnum].z = -10.0; wd->object[objnum].msg = vrShmemStrDup("destination"); objnum++; /* Make a simple maze out of cubes and walls */ wd->number_of_objects = 4; wd->object[objnum].shape = tex_plane; wd->object[objnum].size = 3.0; 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 = 1.0; wd->object[objnum].texture_id = 1; wd->object[objnum].y = 4.0; wd->object[objnum].x = -10.0; wd->object[objnum].z = -1.0; wd->object[objnum].y = 3.0; wd->object[objnum].msg = vrShmemStrDup("billboards"); wd->object[objnum].z = -7.0; objnum++; objnum++; /* Make a simple cylindrical billboard */ wd->object[objnum].shape = tex_cube; wd->object[objnum].shape = billboard_c; wd->object[objnum].size = 3.0; wd->object[objnum].size = 2.0; wd->object[objnum].color[0] = 100; wd->object[objnum].color[0] = 255; 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].texture_id = 1; wd->object[objnum].texture_id = 1; wd->object[objnum].x = -8.0; wd->object[objnum].x = -4.0; wd->object[objnum].y = 4.0; wd->object[objnum].y = 3.0; wd->object[objnum].z = -7.0; wd->object[objnum].z = -4.0; objnum++; objnum++; /* Make a simple spherical billboard */ wd->object[objnum].shape = tex_cube; wd->object[objnum].shape = billboard_s; wd->object[objnum].size = 3.0; wd->object[objnum].size = 2.0; wd->object[objnum].color[0] = 100; wd->object[objnum].color[0] = 255; wd->object[objnum].color[1] = 255; wd->object[objnum].color[2] = 100; wd->object[objnum].texture_id = 1; wd->object[objnum].x = -16.0; wd->object[objnum].y = 3.0; wd->object[objnum].z = -10.0; objnum++; wd->object[objnum].shape = tex_cube; wd->object[objnum].size = 3.0; wd->object[objnum].color[0] = 100; wd->object[objnum].color[1] = 255; wd->object[objnum].color[2] = 100; wd->object[objnum].texture_id = 1; wd->object[objnum].x = 2.0; wd->object[objnum].y = 3.0; wd->object[objnum].z = -10.0; objnum++; wd->object[objnum].shape = tex_cube; wd->object[objnum].size = 3.0; wd->object[objnum].color[0] = 100; wd->object[objnum].color[1] = 255; wd->object[objnum].color[2] = 100; wd->object[objnum].texture_id = 1; wd->object[objnum].x = -10.0; wd->object[objnum].y = 3.0; wd->object[objnum].z = -16.0; objnum++; wd->object[objnum].shape = tex_plane; wd->object[objnum].size = 3.0; wd->object[objnum].color[0] = 100; wd->object[objnum].color[1] = 255; wd->object[objnum].color[2] = 100; wd->object[objnum].texture_id = 1; wd->object[objnum].x = -4.0; wd->object[objnum].y = 3.0; wd->object[objnum].z = -19.0; objnum++; wd->object[objnum].shape = tex_plane; wd->object[objnum].size = 3.0; wd->object[objnum].color[0] = 100; wd->object[objnum].color[1] = 255; wd->object[objnum].color[2] = 100; wd->object[objnum].texture_id = 1; wd->object[objnum].x = 2.0; wd->object[objnum].y = 3.0; wd->object[objnum].z = -19.0; objnum++; wd->object[objnum].shape = tex_plane; wd->object[objnum].size = 3.0; 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].texture_id = 1; wd->object[objnum].texture_id = 1; wd->object[objnum].x = 8.0; wd->object[objnum].x = 8.0; wd->object[objnum].y = 4.0; wd->object[objnum].y = 3.0; wd->object[objnum].z = -7.0; wd->object[objnum].z = -19.0; objnum++; wd->object[objnum].shape = tex_cube; wd->object[objnum].size = 3.0; wd->object[objnum].color[0] = 100; wd->object[objnum].color[1] = 255; wd->object[objnum].color[2] = 100; wd->object[objnum].texture_id = 1; wd->object[objnum].x = 14.0; wd->object[objnum].y = 3.0; wd->object[objnum].z = -16.0; objnum++; wd->object[objnum].shape = tex_cube; wd->object[objnum].size = 3.0; wd->object[objnum].color[0] = 100; wd->object[objnum].color[1] = 255; wd->object[objnum].color[2] = 100; wd->object[objnum].texture_id = 1; wd->object[objnum].x = 14.0; wd->object[objnum].y = 3.0; wd->object[objnum].z = -10.0; objnum++; objnum++; wd->number_of_objects = objnum; wd->number_of_objects = objnum; wd->selected_object = -1; wd->selected_object = -1; /* sanity test */ /* sanity test */ if (objnum > MAX_OBJECTS) { if (objnum > MAX_OBJECTS) { printf("DANGER: Number of objects (%d), exceeds maximum allow printf("DANGER: Number of objects (%d), exceeds maximum allow } } vrLockWriteRelease(wd->lock); vrLockWriteRelease(wd->lock); } } /*******************************************************/ /*******************************************************/ /* end_world(): clean up anything opened by simulation */ /* end_world(): clean up anything opened by simulation */ /*******************************************************/ /*******************************************************/ void end_world() void end_world() { { #ifdef USE_SOCKETS /* { */ #ifdef USE_SOCKETS /* { */ vrSocketClose(listen_sock); vrSocketClose(listen_sock); #endif /* } USE_SOCKETS */ #endif /* } USE_SOCKETS */ } } /*********************************************************************/ /*********************************************************************/ /* 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 #ifdef USE_SOCKETS /* { */ #ifdef USE_SOCKETS /* { */ static char *help_msg = "Socket commands:\n" static char *help_msg = "Socket commands:\n" "\thelp -- this message\n" "\thelp -- this message\n" "\tquit -- quit the application\n" "\tquit -- quit the application\n" "\tclose -- close the connection\n" "\tclose -- close the connection\n" "\treset -- reset the application\n" "\treset -- reset the application\n" "\tmove cube up -- translate the cube up 2 fe "\tmove cube up -- translate the cube up 2 fe "\tmove cube down -- translate the cube down "\tmove cube down -- translate the cube down "\twhere -- report the user's position in the "\twhere -- report the user's position in the "\twhere am i -- report the user's position i "\twhere am i -- report the user's position i "\tshow ActiveWalls -- report some CAVE confi "\tshow ActiveWalls -- report some CAVE confi ""; ""; static int cmd_socket = -1; /* socket to get comm static int cmd_socket = -1; /* socket to get comm static char buf[128]; /* socket read buffer static char buf[128]; /* socket read buffer static char msg[128]; /* socket send buffer static char msg[128]; /* socket send buffer int result; /* result of reading int result; /* result of reading #endif /* } USE_SOCKETS */ #endif /* } USE_SOCKETS */ 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_object_num; /* the object selecte int selected_object_num; /* the object selecte 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 float size; /* size of object -- float size; /* size of 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_time has be last_time = sim_time; /* now that delta_time has be /* 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 if (delta_time <= 0.0) /* can also choose a non-zero 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 */ 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++) { object = &(wd->object[objnum]); object = &(wd->object[objnum]); size = object->size; size = object->size; if ( (wand_vw_location[VR_X] < object->x + size) if ( (wand_vw_location[VR_X] < object->x + size) && (wand_vw_location[VR_X] > object->x - size) && (wand_vw_location[VR_X] > object->x - size) && (wand_vw_location[VR_Y] < object->y + size) && (wand_vw_location[VR_Y] < object->y + size) && (wand_vw_location[VR_Y] > object->y - size) && (wand_vw_location[VR_Y] > object->y - size) && (wand_vw_location[VR_Z] < object->z + size) && (wand_vw_location[VR_Z] < object->z + size) && (wand_vw_location[VR_Z] > object->z - size) ) { && (wand_vw_location[VR_Z] > object->z - size) ) { touch_obj = objnum; touch_obj = objnum; } } } } selected_object_num = wd->selected_object; selected_object_num = wd->selected_object; vrLockReadRelease(wd->lock); vrLockReadRelease(wd->lock); if (selected_object_num != touch_obj) { if (selected_object_num != 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); } } /* 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) && (touch_obj != -1)) { if (vrGet2switchValue(1) && (touch_obj != -1)) { vrLockWriteSet(wd->lock); vrLockWriteSet(wd->lock); object = &(wd->object[touch_obj]); object = &(wd->object[touch_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]; /*********************************/ /* toggle the world-in-miniature */ vrLockWriteSet(wd->lock); wd->show_wim = vrGet2switchValue(2); vrLockWriteRelease(wd->lock); /****************************/ /****************************/ /** Handle Travel via wand **/ /** Handle Travel via wand **/ /****************************/ /****************************/ /* 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, 0, /* walk-throu wand_rw_pointvec.v[VR_Z] * delta_move); wand_rw_pointvec.v[VR_Z] * delta_move); } } /* 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); } } #ifdef USE_SOCKETS /* { */ #ifdef USE_SOCKETS /* { */ /*******************************/ /*******************************/ /* Handle Commands from socket */ /* Handle Commands from socket */ /* if no connection (and a listen socket is open), see if someone is /* if no connection (and a listen socket is open), see if someone is if (cmd_socket < 0 && listen_sock >= 0) { if (cmd_socket < 0 && listen_sock >= 0) { /* cmd_socket will be -1 when no one is connected */ /* cmd_socket will be -1 when no one is connected */ cmd_socket = vrSocketAnswer(listen_sock); cmd_socket = vrSocketAnswer(listen_sock); if (cmd_socket > 0) { if (cmd_socket > 0) { printf("New client connected.\n"); printf("New client connected.\n"); vrSocketSendMsg(cmd_socket, "Your wish is my command vrSocketSendMsg(cmd_socket, "Your wish is my command } } } } /* if a connection, see if client sent a command. If so, act on it * /* if a connection, see if client sent a command. If so, act on it * if (cmd_socket > 0) { if (cmd_socket > 0) { result = vrSocketReadMsgClean(cmd_socket, buf, 128); result = vrSocketReadMsgClean(cmd_socket, buf, 128); switch (result) { switch (result) { case -1: case -1: break; break; case 0: case 0: printf("Client stopped communicating.\n"); printf("Client stopped communicating.\n"); close(cmd_socket); close(cmd_socket); cmd_socket = -1; cmd_socket = -1; break; break; default: default: printf("socket cmd = '%s'\n", buf); printf("socket cmd = '%s'\n", buf); /* parse command here -- very simple-minded parsing * /* parse command here -- very simple-minded parsing * if (strcmp(buf, "quit") == 0) { if (strcmp(buf, "quit") == 0) { /* set the world for termination */ /* set the world for termination */ wd->quit_bit = 1; wd->quit_bit = 1; } else } else if (strcmp(buf, "help") == 0 || strcmp(buf, "?") == 0 if (strcmp(buf, "help") == 0 || strcmp(buf, "?") == 0 /* give usage information */ /* give usage information */ vrSocketSendMsg(cmd_socket, help_msg); vrSocketSendMsg(cmd_socket, help_msg); } else } else if (strcmp(buf, "close") == 0) { if (strcmp(buf, "close") == 0) { /* close socket connection */ /* close socket connection */ printf("Client ending communication.\n"); printf("Client ending communication.\n"); close(cmd_socket); close(cmd_socket); cmd_socket = -1; cmd_socket = -1; } else } else if (strcmp(buf, "reset") == 0) { if (strcmp(buf, "reset") == 0) { /* make the world as it was in the beginning /* make the world as it was in the beginning init_objects(wd); init_objects(wd); vrUserTravelReset(VR_ALLUSERS); vrUserTravelReset(VR_ALLUSERS); } else } else if (strcmp(buf, "move cube up") == 0) { if (strcmp(buf, "move cube up") == 0) { /* move the blue cube up 2.0 units */ /* move the blue cube up 2.0 units */ wd->object[0].y += 2.0; wd->object[0].y += 2.0; } else } else if (strcmp(buf, "move cube down") == 0) { if (strcmp(buf, "move cube down") == 0) { /* move the blue cube down 2.0 units */ /* move the blue cube down 2.0 units */ wd->object[0].y -= 2.0; wd->object[0].y -= 2.0; } else } else if (strcmp(buf, "where") == 0 || strcmp(buf, "where a if (strcmp(buf, "where") == 0 || strcmp(buf, "where a /* report the user's location */ /* report the user's location */ vrMatrix *headmat; vrMatrix *headmat; vrPoint headloc; vrPoint headloc; headmat = vrMatrixCreate(); headmat = vrMatrixCreate(); vrMatrixGetRWFromUserHead(headmat, 0); vrMatrixGetRWFromUserHead(headmat, 0); vrPointGetVWFromUserMatrix(&headloc, 0, headm vrPointGetVWFromUserMatrix(&headloc, 0, headm sprintf(msg, "You are at (%f %f %f).\n", head sprintf(msg, "You are at (%f %f %f).\n", head vrSocketSendMsg(cmd_socket, msg); vrSocketSendMsg(cmd_socket, msg); } else } else if (strcmp(buf, "show ActiveWalls") == 0) { if (strcmp(buf, "show ActiveWalls") == 0) { /* report the type of graphics (VR) display * /* report the type of graphics (VR) display * sprintf(msg, "Application has %d active walls sprintf(msg, "Application has %d active walls vrSocketSendMsg(cmd_socket, msg); vrSocketSendMsg(cmd_socket, msg); } else } else /* default: */ { /* default: */ { vrSocketSendMsg(cmd_socket, "Unknown command. vrSocketSendMsg(cmd_socket, "Unknown command. } } /* prompt for another command (if socket still open) /* prompt for another command (if socket still open) if (cmd_socket > 0) { if (cmd_socket > 0) { vrSocketSendMsg(cmd_socket, "Your wish is my vrSocketSendMsg(cmd_socket, "Your wish is my } } } } } } #endif /* } USE_SOCKETS */ #endif /* } USE_SOCKETS */ /*********************************/ /*********************************/ /* Handle Commands from keyboard */ /* Handle Commands from keyboard */ if (vrGet2switchValue(0)) { if (vrGet2switchValue(0)) { wd->quit_bit = 1; 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 wrs_shapes.c */ /* functions from wrs_shapes.c */ void draw_floor(); void draw_floor(); void draw_cube(); void draw_cube(); void draw_sphere(); void draw_sphere(); void draw_pyramid(); void draw_pyramid(); void draw_plane(); void draw_plane(); void draw_cube_outline(); void draw_cube_outline(); void draw_sphere_outline(); void draw_sphere_outline(); void draw_pyramid_outline(); void draw_pyramid_outline(); void draw_plane_outline(); void draw_plane_outline(); void *make_texture_checker_pattern(int xsize, int ysize, int trans); void *make_texture_checker_pattern(int xsize, int ysize, int trans); void set_texture_image(void *imagedata); void set_texture_image(void *imagedata); void *readPPM(char *filename); void *readPPM(char *filename); /*********************************************************************/ /*********************************************************************/ /* init_gfx(): initialize general graphics properties (eg. lighting) */ /* init_gfx(): initialize general graphics properties (eg. lighting) */ /*********************************************************************/ /*********************************************************************/ void init_gfx() 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 }; void *imagedata; void *imagedata; /****************************************/ /****************************************/ /* 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 call glEnable(GL_NORMALIZE); /* this is required when call /***************************/ /***************************/ /* set the line parameters */ /* set the line parameters */ glEnable(GL_LINE_SMOOTH); glEnable(GL_LINE_SMOOTH); glLineWidth(2.0); glLineWidth(2.0); /*********************************************************/ /*********************************************************/ /* set the alpha parameters for see-through texture maps */ /* set the alpha parameters for see-through texture maps */ glEnable(GL_ALPHA_TEST); /* when using transparencies glEnable(GL_ALPHA_TEST); /* when using transparencies glAlphaFunc(GL_GREATER, 0.5); glAlphaFunc(GL_GREATER, 0.5); /**********************************/ /**********************************/ /* create and set the texture map */ /* create and set the texture map */ imagedata = make_texture_checker_pattern(4, 4, 0); imagedata = make_texture_checker_pattern(4, 4, 0); glBindTexture(GL_TEXTURE_2D, 1); glBindTexture(GL_TEXTURE_2D, 1); set_texture_image(imagedata); set_texture_image(imagedata); } } /*******************************************************************/ /**********************************************************************/ /* draw_world(): Now will render how ever many objects are in the */ /* render_virtualworld(): Render just the objects that are considered */ /* world data structure. The color, type (and maybe rotation) */ /* a part of the virtual world. Ie. excluding user interface stuff.*/ /* are all now stored for each object, in addition to location. */ /**********************************************************************/ /* The currently selected object is highlighted by adding a */ void render_virtualworld(WorldDataType *wd, vrRenderInfo *rendinfo) /* wireframe outline to the representation. */ /*******************************************************************/ void draw_world(WorldDataType *wd, vrRenderInfo *rendinfo) { { static GLfloat location_0[4] = { 0.0, 10.0, 0.0, 1.0 /* 0 = directio int objnum; /* object counter */ int objnum; /* object counter */ ObjectType *object; /* pointer to current ObjectType *object; /* pointer to current float size; /* size of current ob double size; /* size of current ob vrEuler angles; /* used for billboard /**************************************/ /* clear the screen -- very important */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /******************************************************************** /* update the light's location -- must be done independently for each glLightfv(GL_LIGHT0, GL_POSITION, location_0); /************************************/ /* draw a short pointer at the wand */ glPushMatrix(); glColor3ub(100, 255, 255); /* cyan */ vrRenderTransform6sensor(rendinfo, WAND_SENSOR); glRotatef(-90.0, 1.0, 0.0, 0.0); glScalef(0.15, 0.15, 0.15); glTranslatef(0.0, 1.5, 0.0); draw_pyramid_outline(); glPopMatrix(); /*******************************************************/ /*****************************************/ /* draw an object that remains fixed in physical space */ /* draw the objects in the virtual world */ glColor3ub(200, 100, 255); /* purple */ glPushMatrix(); glPushMatrix(); glTranslatef(-4.0, 1.0, -1.0); glScalef(5.0, 5.0, 5.0); draw_cube(); draw_floor(); glPopMatrix(); glPopMatrix(); /******************************************************************/ /* draw the rest of the objects in virtual (user navigated) space */ glPushMatrix(); /* save the real-world coordi vrRenderTransformUserTravel(rendinfo); /* change to virtual-world co draw_floor(); vrLockReadSet(wd->lock); /* lock while reading info ab vrLockReadSet(wd->lock); /* lock while reading info ab for (objnum = 0; objnum < wd->number_of_objects; objnum++) { for (objnum = 0; objnum < wd->number_of_objects; objnum++) { object = &(wd->object[objnum]); object = &(wd->object[objnum]); glColor3ubv(object->color); glColor3ubv(object->color); glPushMatrix(); glPushMatrix(); size = object->size; size = object->size; glTranslatef(object->x, object->y, object->z); glTranslatef(object->x, object->y, object->z); glScalef(size, size, size); glScalef(size, size, size); switch (object->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 tex_cube: case tex_cube: glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, object->texture_ glBindTexture(GL_TEXTURE_2D, object->texture_ if (objnum == wd->selected_object) if (objnum == wd->selected_object) draw_cube_outline(); draw_cube_outline(); else draw_cube(); else draw_cube(); glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D); break; break; case tex_plane: case tex_plane: glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, object->texture_ glBindTexture(GL_TEXTURE_2D, object->texture_ if (objnum == wd->selected_object) if (objnum == wd->selected_object) draw_plane_outline(); draw_plane(); else draw_plane_outline(); else draw_plane_outline(); glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D); break; break; case sphere: case sphere: if (objnum == wd->selected_object) if (objnum == wd->selected_object) draw_sphere_outline(); draw_sphere_outline(); else draw_sphere(); else draw_sphere(); 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; case billboard_c: vrRenderGetBillboardAngles3d(rendinfo, &angle glRotatef(angles.r[VR_AZIM], 0.0, 1.0, 0.0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, object->texture_ if (objnum == wd->selected_object) draw_plane(); else draw_plane_outline(); glDisable(GL_TEXTURE_2D); break; case billboard_s: vrRenderGetBillboardAngles3d(rendinfo, &angle glRotatef(angles.r[VR_AZIM], 0.0, 1.0, 0.0); glRotatef(angles.r[VR_ELEV], 1.0, 0.0, 0.0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, object->texture_ if (objnum == wd->selected_object) draw_plane(); else draw_plane_outline(); glDisable(GL_TEXTURE_2D); break; case text: case text: glDisable(GL_LIGHTING); glDisable(GL_LIGHTING); glRasterPos3f(0.0, 0.0, 0.0); glRasterPos3f(0.0, 0.0, 0.0); #if TEXT_STYLE == X_2DTEXT /* { */ #if TEXT_STYLE == X_2DTEXT /* { */ /* Render text as a 2D bitmap using X-windows /* Render text as a 2D bitmap using X-windows /* NOTE: if the beginning of the string is cl /* NOTE: if the beginning of the string is cl /* none of the characters will appear. /* none of the characters will appear. vrRenderText(rendinfo, object->msg); vrRenderText(rendinfo, object->msg); #elif TEXT_STYLE == GLUT_2DTEXT #elif TEXT_STYLE == GLUT_2DTEXT /* Render text as a 2D bitmap using the GLUT /* Render text as a 2D bitmap using the GLUT /* NOTE: if the beginning of the string is cl /* NOTE: if the beginning of the string is cl /* none of the characters will appear. /* none of the characters will appear. { { char *chr; char *chr; for (chr = object->msg; *chr; chr++) for (chr = object->msg; *chr; chr++) glutBitmapCharacter(GLUT_BITMAP_9_BY_ glutBitmapCharacter(GLUT_BITMAP_9_BY_ } } #elif TEXT_STYLE == GLUT_3DTEXT #elif TEXT_STYLE == GLUT_3DTEXT /* Render text as a flat, but 3D stroke font /* Render text as a flat, but 3D stroke font glScalef(0.01, 0.01, 0.01); glScalef(0.01, 0.01, 0.01); { { char *chr; char *chr; for (chr = object->msg; *chr; chr++) for (chr = object->msg; *chr; chr++) glutStrokeCharacter(GLUT_STROKE_ROMAN glutStrokeCharacter(GLUT_STROKE_ROMAN } } #endif /* } TEXT_STYLE */ #endif /* } TEXT_STYLE */ glEnable(GL_LIGHTING); glEnable(GL_LIGHTING); break; break; } } glPopMatrix(); glPopMatrix(); } } vrLockReadRelease(wd->lock); vrLockReadRelease(wd->lock); } glPopMatrix(); /* return to real-world coordinates */ /***************************************************************************/ /* draw_world(): Render all the objects fixed in real world positoins, */ /* and objects located in the virtual world (via render_virtualworld()). */ /***************************************************************************/ void draw_world(WorldDataType *wd, vrRenderInfo *rendinfo) { static GLfloat location_0[4] = { 0.0, 10.0, 0.0, 1.0 /* 0 = directio int show_wim; /**************************************/ /* clear the screen -- very important */ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); /******************************************************************** /* update the light's location -- must be done independently for each glLightfv(GL_LIGHT0, GL_POSITION, location_0); /*******************************************************/ /* draw a short pointer or miniature world at the wand */ vrLockReadSet(wd->lock); show_wim = wd->show_wim; vrLockReadRelease(wd->lock); glPushMatrix(); glColor3ub(100, 255, 255); /* cyan */ vrRenderTransform6sensor(rendinfo, WAND_SENSOR); if (show_wim) { /* the world-in-miniature replaces the wand avatar */ glScalef(0.025, 0.025, 0.025); render_virtualworld(wd, rendinfo); /* draw a sphere at the user's location */ glColor3ub(100, 255, 255); /* cyan */ /* factor OUT the head relative to the world */ vrRenderTransformUserTravelInv(rendinfo); vrRenderTransform6sensor(rendinfo, HEAD_SENSOR); draw_sphere(); } else { glRotatef(-90.0, 1.0, 0.0, 0.0); glScalef(0.15, 0.15, 0.15); glTranslatef(0.0, 1.5, 0.0); draw_pyramid_outline(); } glPopMatrix(); /*******************************************************/ /* draw an object that remains fixed in physical space */ glColor3ub(200, 100, 255); /* purple */ glPushMatrix(); glTranslatef(-4.0, 1.0, -1.0); draw_cube(); glPopMatrix(); /******************************************/ /* Now render the full-size virtual world */ vrRenderTransformUserTravel(rendinfo); /* change to virtual-world co render_virtualworld(wd, rendinfo); } }