Joerg Wallmersperger (joerg++at++zaphod.munich.sgi.com)
Tue, 9 Sep 1997 09:52:23 +0200
Yes, there is a driver for the XInputExtension available which comes
along with Irix 6.x. Install
eoe.sw.optinput
For more information regarding driver software examples look at
http://dv.op.dlr.de/FF-DR-RS/SC/software/index.html
} 2.) I'm wondering how many if any Performers are using either
} these devices in their App.'s and if so could they describe
} what they had to do to get them working (without Vega).
I attached a small C++ program, which is an extension to complex.C. All
Magellan related lines are enclosed in #ifdef SPACEMOUSE ... #endif
directives. The example uses XInput.h.
Greetings
Joerg
-- Joerg Wallmersperger Silicon Graphics GmbH, Am Hochacker 3, 85630 Grasbrunn E-mail: joerg++at++munich.sgi.com Tel.: 089-46108314 (US: 49.89.46108314) Fax.: 089-46107314 (US: 49.89.46107314) http://reality.sgi.com/joerg_munich
#!smake -J 1 #-------------------------------------------------------------------# #-- Makefile for Performer/src/pguide/libpf/C++ directory --# #-------------------------------------------------------------------# #-- RCS version information --# #-- $Revision: 1.57 $ --# #-- $Date: 1995/11/29 00:56:32 $ --# #-------------------------------------------------------------------#
#-------------------------------------------------------------------# #-- The default make target makes the IRISGL Dynamic Shared Object.-# #-- The targets are: --# #-- build debugging versions: igldbg (or ogldbg) --# #-- build optimized versions: iglopt (or oglopt) --# #-- build dynamic shared object versions: igldso ogldso --# #-- build debugging dynamic shared object versions: --# #-- iglddso oglddso --# #-- remove all unneeded files after a build: clean --# #-- remove all machine generated files: clobber --# #-- --# #-- --# #-------------------------------------------------------------------#
#-- #-- definitions #--
#if !defined(PFSTYLE) PFSTYLE = 32 #endif #if $(PFSTYLE) == "64" OBJECT_STYLE = 64 LIBBITSUF=64 PFRELEASE=N64 #endif #if $(PFSTYLE) == "N32" OBJECT_STYLE = N32_M3 LIBBITSUF=32 PFRELEASE=N32 #endif #if $(PFSTYLE) == "32" OBJECT_STYLE = 32 LIBBITSUF= PFRELEASE=O32 #endif
include $(ROOT)/usr/include/make/commondefs C++FLAGS += -DSPACEMOUSE -DSTEREO PFROOT ?= $(ROOT)
DSOLINKS = \ -L$(PFROOT)/usr/lib$(LIBBITSUF) \ -L$(PFROOT)/usr/lib$(LIBBITSUF)/libpfdb \ -L$(PFROOT)/lib$(LIBBITSUF)
DDSOLINKS = \ -L$(PFROOT)/usr/lib$(LIBBITSUF)/Performer/Debug \ -L$(PFROOT)/usr/lib$(LIBBITSUF)/Performer/Debug/libpfdb \ -L$(PFROOT)/lib$(LIBBITSUF)
DBGLINKS = \ -L$(PFROOT)/usr/lib$(LIBBITSUF)/Performer/DebugStatic \ -L$(PFROOT)/usr/lib$(LIBBITSUF)/Performer/DebugStatic/libpfdb \ -L$(PFROOT)/lib$(LIBBITSUF)
OPTLINKS = \ -L$(PFROOT)/usr/lib$(LIBBITSUF)/Performer/Static \ -L$(PFROOT)/usr/lib$(LIBBITSUF)/Performer/Static/libpfdb \ -L$(PFROOT)/lib$(LIBBITSUF)
IGLLIB = -ignore_unresolved -lpf_igl -lpfdu_igl -lpfui -lpfutil_igl OGLLIB = -ignore_unresolved -lpf_ogl -lpfdu_ogl -lpfui -lpfutil_ogl
#if defined(PFSTATIC_CONVERTERS) IGLLIB += -all $(PFSTATIC_CONVERTERS) -none OGLLIB += -all $(PFSTATIC_CONVERTERS) -none #endif
LIBIRISGL = -lgl LIBOPENGL = -lGLU -lGL -lXext
SYSTEM_IRISGL = \ -lmpc \ -limage \ -lfm \ ${LIBIRISGL} \ -lXirisw \ -lXi \ -lXsgivc \ -lXm \ -lXt \ -lfpe \ -lXmu \ -lX11 \ -lm \ -lmalloc \ -lC
SYSTEM_OPENGL = \ -lmpc \ -limage \ -lGLw \ ${LIBOPENGL} \ -lfpe \ -lXi \ -lXsgivc \ -lXm \ -lXt \ -lXmu \ -lX11 \ -lm \ -lmalloc \ -lC
#if $(PFSTYLE) == "64" SYSTEM_OPENGL = \ -limage \ ${LIBOPENGL} \ -lXsgivc \ -lXi \ -lXmu \ -lX11 \ -lm \ -lC #endif
#if $(PFSTYLE) == "N32" SYSTEM_IRISGL = \ -limage \ ${LIBIRISGL} \ -lXi \ -lXmu \ -lX11 \ -lm \ -lfm \ -lC
SYSTEM_OPENGL = \ -limage \ ${LIBOPENGL} \ -lXsgivc \ -lXi \ -lXmu \ -lX11 \ -lm \ -lC #endif
#-- targets are the executables TARGETS = \ stereofly \ spacefly
OBJECTS = \ $(TARGETS:=.o)\ culldl.o
#-- #-- #-- generic targets #--
#-- make optimized dso version of program by default default: oglopt
#-- synonym targets debug: igldbg
optimize: iglopt
#-- make all versions of program all: igldbg iglopt igldso iglddso ogldbg oglopt ogldso oglddso
#if $(PFSTYLE) == "64" #-- make optimized dso version of program by default default: ogldso
#-- synonym targets debug: ogldbg
optimize: oglopt
#-- make all versions of program all: ogldbg oglopt ogldso oglddso #endif
igldso: $(TARGETS:=.igldso) iglopt: $(TARGETS:=.iglopt) igldbg: $(TARGETS:=.igldbg) iglddso: $(TARGETS:=.iglddso)
ogldso: $(TARGETS:=.ogldso) oglopt: $(TARGETS:=.oglopt) ogldbg: $(TARGETS:=.ogldbg) oglddso: $(TARGETS:=.oglddso)
#-- clean up directories {remove junk} clean: if test -d DBG.$(PFRELEASE).IRISGL; then cd DBG.$(PFRELEASE).IRISGL ; rm -f ${OBJECTS} core ; cd .. ; fi if test -d DBG.$(PFRELEASE).OPENGL; then cd DBG.$(PFRELEASE).OPENGL ; rm -f ${OBJECTS} core ; cd .. ; fi if test -d OPT.$(PFRELEASE).IRISGL; then cd OPT.$(PFRELEASE).IRISGL ; rm -f ${OBJECTS} core ; cd .. ; fi if test -d OPT.$(PFRELEASE).OPENGL; then cd OPT.$(PFRELEASE).OPENGL ; rm -f ${OBJECTS} core ; cd .. ; fi
#-- remove all machine-built files clobber: clean if test -d OPT.$(PFRELEASE).IRISGL ; then rm -rf OPT.$(PFRELEASE).IRISGL ; fi if test -d OPT.$(PFRELEASE).OPENGL ; then rm -rf OPT.$(PFRELEASE).OPENGL ; fi if test -d DBG.$(PFRELEASE).IRISGL ; then rm -rf DBG.$(PFRELEASE).IRISGL ; fi if test -d DBG.$(PFRELEASE).OPENGL ; then rm -rf DBG.$(PFRELEASE).OPENGL ; fi rm -f ${TARGETS}
#-- #-- library targets #--
$(TARGETS): $(++at++:=.igldso)
$(TARGETS:=.igldbg): .MAKE ++at++echo "\nmaking IrisGL DBG version of $++at++" ++at++if test ! -d DBG.$(PFRELEASE).IRISGL ; then mkdir -p DBG.$(PFRELEASE).IRISGL ; fi ++at++ rm -f $(++at++:S/.igldbg//) ++at++cd DBG.$(PFRELEASE).IRISGL ; \ ${MAKE} -f ../Makefile OPTIMIZER=-g LCDEFS=-DIRISGL LCXXDEFS=-DIRISGL \ LIBRARIES='$(IGLLIB) ${SYSTEM_IRISGL}' \ $(++at++:S/igl//)cmd ; ++at++echo "making symbolic links to DBG versions" ln -s DBG.$(PFRELEASE).IRISGL/$(++at++:S/igl//)cmd $(++at++:S/.igldbg//) ;
$(TARGETS:=.iglopt): .MAKE ++at++echo "\nmaking IrisGL OPT version of $++at++" ++at++if test ! -d OPT.$(PFRELEASE).IRISGL ; then mkdir -p OPT.$(PFRELEASE).IRISGL ; fi ++at++ rm -f $(++at++:S/.iglopt//) ++at++cd OPT.$(PFRELEASE).IRISGL ; \ ${MAKE} -f ../Makefile OPTIMIZER="-O -Olimit 2000" LCDEFS=-DIRISGL LCXXDEFS=-DIRISGL \ LIBRARIES='$(IGLLIB) ${SYSTEM_IRISGL}' \ $(++at++:S/igl//)cmd ; cd .. ++at++echo "making symbolic links to OPT versions" ln -s OPT.$(PFRELEASE).IRISGL/$(++at++:S/igl//)cmd $(++at++:S/.iglopt//) ;
$(TARGETS:=.igldso): .MAKE ++at++echo "\nmaking IrisGL DSO version of $++at++" ++at++if test ! -d OPT.$(PFRELEASE).IRISGL ; then mkdir -p OPT.$(PFRELEASE).IRISGL ; fi ++at++ rm -f $(++at++:S/.igldso//) ++at++cd OPT.$(PFRELEASE).IRISGL ; \ ${MAKE} -f ../Makefile OPTIMIZER="-O -Olimit 2000" LCDEFS=-DIRISGL LCXXDEFS=-DIRISGL \ LIBRARIES='$(IGLLIB) ${SYSTEM_IRISGL}' \ $(++at++:S/igl//)cmd ; cd .. ++at++echo "making symbolic links to DSO versions" ln -s OPT.$(PFRELEASE).IRISGL/$(++at++:S/igl//)cmd $(++at++:S/.igldso//) ;
$(TARGETS:=.iglddso): .MAKE ++at++echo "\nmaking IrisGL DDSO version of $++at++" ++at++if test ! -d DBG.$(PFRELEASE).IRISGL ; then mkdir -p DBG.$(PFRELEASE).IRISGL ; fi ++at++ rm -f $(++at++:S/.iglddso//) ++at++cd DBG.$(PFRELEASE).IRISGL ; \ ${MAKE} -f ../Makefile OPTIMIZER=-g LCDEFS=-DIRISGL LCXXDEFS=-DIRISGL \ LIBRARIES='$(IGLLIB) ${SYSTEM_IRISGL}' \ $(++at++:S/igl//)cmd ; cd .. ++at++echo "making symbolic links to DDSO versions" ln -s DBG.$(PFRELEASE).IRISGL/$(++at++:S/igl//)cmd $(++at++:S/.iglddso//) ;
$(TARGETS:=.ogldbg): .MAKE ++at++echo "\nmaking OpenGL DBG version of $++at++" ++at++if test ! -d DBG.$(PFRELEASE).OPENGL ; then mkdir -p DBG.$(PFRELEASE).OPENGL ; fi ++at++ rm -f $(++at++:S/.ogldbg//) ++at++cd DBG.$(PFRELEASE).OPENGL ; \ ${MAKE} -f ../Makefile OPTIMIZER="-g " \ LIBRARIES='$(OGLLIB) ${SYSTEM_OPENGL}' \ $(++at++:S/ogl//)cmd ; cd .. ++at++echo "making symbolic links to DBG versions" ln -s DBG.$(PFRELEASE).OPENGL/$(++at++:S/ogl//)cmd $(++at++:S/.ogldbg//) ;
$(TARGETS:=.oglopt): .MAKE ++at++echo "\nmaking OpenGL OPT version of $++at++" ++at++if test ! -d OPT.$(PFRELEASE).OPENGL ; then mkdir -p OPT.$(PFRELEASE).OPENGL ; fi ++at++ rm -f $(++at++:S/.oglopt//) ++at++cd OPT.$(PFRELEASE).OPENGL ; \ ${MAKE} -f ../Makefile OPTIMIZER="-O -Olimit 2000" \ LIBRARIES='$(OGLLIB) ${SYSTEM_OPENGL}' \ $(++at++:S/ogl//)cmd ; cd .. ++at++echo "making symbolic links to OPT versions" ln -s OPT.$(PFRELEASE).OPENGL/$(++at++:S/ogl//)cmd $(++at++:S/.oglopt//) ;
$(TARGETS:=.ogldso): .MAKE ++at++echo "\nmaking OpenGL DSO version of $++at++" ++at++if test ! -d OPT.$(PFRELEASE).OPENGL ; then mkdir -p OPT.$(PFRELEASE).OPENGL ; fi ++at++ rm -f $(++at++:S/.ogldso//) ++at++cd OPT.$(PFRELEASE).OPENGL ; \ ${MAKE} -f ../Makefile OPTIMIZER="-O -Olimit 2000" \ LIBRARIES='$(OGLLIB) ${SYSTEM_OPENGL}' \ $(++at++:S/ogl//)cmd ; cd .. ++at++echo "making symbolic links to DSO versions" ln -s OPT.$(PFRELEASE).OPENGL/$(++at++:S/ogl//)cmd $(++at++:S/.ogldso//);
$(TARGETS:=.oglddso): .MAKE ++at++echo "\nmaking OpenGL DDSO version of $++at++" ++at++if test ! -d DBG.$(PFRELEASE).OPENGL ; then mkdir -p DBG.$(PFRELEASE).OPENGL ; fi ++at++ rm -f $(++at++:S/.oglddso//) ++at++cd DBG.$(PFRELEASE).OPENGL ; \ ${MAKE} -f ../Makefile OPTIMIZER="-g " \ LIBRARIES='$(OGLLIB) ${SYSTEM_OPENGL}' \ $(++at++:S/ogl//)cmd ; cd .. ++at++echo "making symbolic links to DDSO versions" ln -s DBG.$(PFRELEASE).OPENGL/$(++at++:S/ogl//)cmd $(++at++:S/.oglddso//);
dso: igldso ddso: iglddso dbg: igldbg opt: iglopt
#-- #-- internal targets #--
.SUFFIXES: .dbgcmd .optcmd .dsocmd .ddsocmd
.o.dbgcmd: ${CC} ${CFLAGS} -o $++at++ $< $(DBGLINKS) -all ${LIBRARIES}
.o.optcmd: ${CC} ${CFLAGS} -o $++at++ $< $(OPTLINKS) -all ${LIBRARIES}
.o.dsocmd: ${CC} ${CFLAGS} -o $++at++ $< $(DSOLINKS) -all ${LIBRARIES}
.o.ddsocmd: ${CC} ${CFLAGS} -o $++at++ $< $(DDSOLINKS) -all ${LIBRARIES}
#-- #-- internal targets #--
#-- look for sources in this dir when recursing .PATH: ..
// // Copyright 1995, Silicon Graphics, Inc. // ALL RIGHTS RESERVED // // UNPUBLISHED -- Rights reserved under the copyright laws of the United // States. Use of a copyright notice is precautionary only and does not // imply publication or disclosure. // // U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND: // Use, duplication or disclosure by the Government is subject to restrictions // as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights // in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or // in similar or successor clauses in the FAR, or the DOD or NASA FAR // Supplement. Contractor/manufacturer is Silicon Graphics, Inc., // 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311. // // Permission to use, copy, modify, distribute, and sell this software // and its documentation for any purpose is hereby granted without // fee, provided that (i) the above copyright notices and this // permission notice appear in all copies of the software and related // documentation, and (ii) the name of Silicon Graphics may not be // used in any advertising or publicity relating to the software // without the specific, prior written permission of Silicon Graphics. // // THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, // EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY // WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. // // IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, // INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY // DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, // WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY // THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE // OR PERFORMANCE OF THIS SOFTWARE. // // // spacefly.C // ------------ // // is based on the Performer example complex.C and includes support // for the spacemouse device. // // new command line options are // // -s translation_speed; > 1.0 more translation speed, 0..1 less speed // // if runs in stereo mode // // -i <interocular distance>; default is 0.07 // // new run-time controls are // // +-<numeric keypad>: increase interocular distance // --<numeric keypad>: decrease interocular distance // // For further information on spacemouse // devices watch out for // // http://dv.op.dlr.de/FF-DR-RS/SC // // If the compiler directives SPACEMOUSE and SPACEMOUSE_DEBUG are // omitted the program behaves like 'complex'. // // spacemouse and stereo code was added by // Andreas Loesch <andreas++at++munich.sgi.com> // and Joerg Wallmersperger <joerg++at++munich.sgi.com> // // complex.C documentation: // ------------------------ // IRIS Performer example using cull and draw process callbacks. // Mouse and keyboard go through GL which is simpler than mixed // model (GLX), but does incur some overhead in the draw process. // X input handling is done in a forked event handling process. // // $Revision: 1.18 $ // $Date: 1996/12/18 03:49:02 $ // // Command-line options: // -b : norborder window // -f : full screen // -F : put X input handling in a forked process // -m procsplit : multiprocess mode // -w : write scene to file // // // Run-time controls: // ESC-key: exits // F1-key: profile // Left-mouse: advance // Middle-mouse: stop // Right-mouse: retreat
#include <stdlib.h> #include <string.h> #include <math.h> #include <signal.h> // for sigset for forked X event handler process #include <getopt.h> // for cmdline handler #include <X11/keysym.h> #ifdef IRISGL #include <gl/device.h> #endif // GL type
#include <Performer/pf/pfNode.h> #include <Performer/pf/pfPipe.h> #include <Performer/pf/pfChannel.h>
#include <Performer/pr/pfLight.h>
#include <Performer/pfutil.h> #include <Performer/pfdu.h> #ifdef SPACEMOUSE #include <X11/extensions/XInput.h> #endif // // structure that resides in shared memory so that the // application, cull, and draw processes can access it.
typedef struct { pfPipeWindow *pw; int exitFlag; int inWindow, reset; float mouseX, mouseY; int winSizeX, winSizeY; int mouseButtons; pfCoord view, viewOrig; float accelRate; float sceneSize; int drawStats; int XInputInited; #ifdef SPACEMOUSE int spacemouse; pfCoord spacecoord; float smousefactor; XDevice *spaceMouseDev; #endif #ifdef STEREO int stereo; #endif } SharedData;
static SharedData *Shared;
#ifdef SPACEMOUSE int MagellanMotionEventType, MagellanButtonPressEventType, MagellanButtonReleaseEventType, MagellanMotionEventClass, MagellanButtonPressEventClass, MagellanButtonReleaseEventClass; XEventClass ListOfEventClass[3]; float transSpeed = 1.0; #endif #ifdef STEREO int frustrumChanged = FALSE; static float Iod = .07f; static int FBAttrs[] = { PFFB_RGBA, PFFB_DOUBLEBUFFER, PFFB_STEREO, PFFB_DEPTH_SIZE, 23, PFFB_RED_SIZE, 1, PFFB_STENCIL_SIZE, 1, None, }; #endif static float Fov = 45.f; // // APP process variables
// for configuring multi-process static int ProcSplit = PFMP_DEFAULT; // write out scene upon read-in - uses pfDebugPrint static int WriteScene = 0; static int FullScreen = 0; static int WinType = PFPWIN_TYPE_X; static int NoBorder = 0; static int ForkedXInput = 0; float far = 10000.0f; float near = .1f; char ProgName[PF_MAXSTRING]; // light source created and updated in DRAW-process static pfLight *Sun;
static void CullChannel(pfChannel *chan, void *data); static void DrawChannel(pfChannel *chan, void *data); static void OpenPipeWin(pfPipeWindow *pw); static void UpdateView(void); static void GetGLInput(void); static void InitXInput(pfWSConnection dsp); static void DoXInput(void); static void GetXInput(Display *dsp); static void Usage(void); #ifdef SPACEMOUSE static void initSpaceMouse(void); #endif #ifdef STEREO void initializeFrustrum(pfChannel *, pfChannel *); #endif
// // Usage() -- print usage advice and exit. This procedure // is executed in the application process.
static void Usage (void) { pfNotify(PFNFY_FATAL, PFNFY_USAGE, "\ Usage: %s [-s translation_speed] [-i IOD] [-m procSplit] [-f] [-F] [-b]\ [-w] [file.ext ...]\n", ProgName); exit(1); }
// // docmdline() -- use getopt to get command-line arguments, // executed at the start of the application process.
static int docmdline(int argc, char *argv[]) { int opt; strcpy(ProgName, argv[0]); // process command-line arguments while ((opt = getopt(argc, argv, "s:fFbm:wxp:?")) != -1) { switch (opt) { case 'f': FullScreen = 1; break; case 'F': ForkedXInput = 1; break; case 'm': case 'p': ProcSplit = atoi(optarg); break; case 'w': WriteScene = 1; break; case 'x': WinType &= ~(PFPWIN_TYPE_X); break; case 'b': NoBorder ^= 1; break; #ifdef SPACEMOUSE case 's': transSpeed = atof(optarg); break; #endif #ifdef STEREO case 'i': /* get interocular distance */ Iod = atof(optarg); break; case 'v': /* get field of view */ Fov = atof(optarg); break; #endif case '?': case 'h': Usage(); } } return optind; }
// // main() -- program entry point. this procedure // is executed in the application process.
int main (int argc, char *argv[]) { int arg; int found; pfBox bbox;
pfWSConnection dsp=NULL; #ifdef SPACEMOUSE pfMatrix mat1,mat2; #endif #ifdef STEREO unsigned int mask; int *leftArg, *rightArg; #endif arg = docmdline(argc, argv); pfInit(); // configure multi-process selection pfMultiprocess(ProcSplit); // allocate shared before fork()'ing parallel processes Shared = (SharedData*)pfMalloc(sizeof(SharedData), pfGetSharedArena()); Shared->inWindow = 0; Shared->reset = 0; Shared->exitFlag = 0; Shared->drawStats = 1; Shared->XInputInited = 0; // Load all loader DSO's before pfConfig() forks for (found = arg; found < argc; found++) pfdInitConverter(argv[found]);
// initiate multi-processing mode set in pfMultiprocess call // FORKs for Performer processes, CULL and DRAW, etc. happen here. pfConfig(); // configure pipes and windows Shared->pw = new pfPipeWindow(pfGetPipe(0)); Shared->pw->setName("IRIS Performer"); Shared->pw->setWinType(WinType); if (NoBorder) Shared->pw->setMode(PFWIN_NOBORDER, 1); // Open and configure the GL window. Shared->pw->setConfigFunc(OpenPipeWin); Shared->pw->config(); if (FullScreen) Shared->pw->setFullScreen(); else Shared->pw->setOriginSize(0, 0, 300, 300); // set off the draw process to open windows and call init callbacks pfFrame(); // create forked XInput handling process // since the Shared pointer has already been initialized, that structure // will be visible to the XInput process. Nothing else created in the // application after this fork whose handles are not put in shared memory // (such as the database and channels) will be visible to the // XInput process. if (WinType & PFPWIN_TYPE_X) { pid_t fpid = 0; if (ForkedXInput) { if ((fpid = fork()) < 0) pfNotify(PFNFY_FATAL, PFNFY_SYSERR, "Fork of XInput process failed."); else if (fpid) pfNotify(PFNFY_NOTICE,PFNFY_PRINT,"XInput running in forked process %d", fpid); else if (!fpid) DoXInput(); } else { dsp = pfGetCurWSConnection(); } } // specify directories where geometry and textures exist if (!(getenv("PFPATH"))) pfFilePath( "." ":./data" ":../data" ":../../data" ":/usr/share/Performer/data" ); pfNotify(PFNFY_INFO, PFNFY_PRINT,"FilePath: %s\n", pfGetFilePath()); // load files named by command line arguments pfScene *scene = new pfScene(); for (found = 0; arg < argc; arg++) { pfNode *root; if ((root = pfdLoadFile(argv[arg])) != NULL) { scene->addChild(root); found++; } } // if no files successfully loaded, terminate program #if 0 if (!found) Usage(); #endif // Write out nodes in scene (for debugging) if (WriteScene) { FILE *fp; if (fp = fopen("scene.out", "w")) { pfPrint(scene, PFTRAV_SELF|PFTRAV_DESCEND, PFPRINT_VB_DEBUG, fp); fclose(fp); } else pfNotify(PFNFY_WARN, PFNFY_RESOURCE, "Could not open scene.out for debug printing."); } // determine extent of scene's geometry pfuTravCalcBBox(scene, &bbox); pfFrameRate(30.0f); pfPhase(PFPHASE_FREE_RUN); #ifdef STEREO
/* create a channel for each eye */ pfChannel *left = new pfChannel(pfGetPipe(0)); pfChannel *chan = left; pfChannel *right = new pfChannel(pfGetPipe(0)); left->attach(right); mask = left->getShare();
/* same viewport */ mask |= PFCHAN_VIEWPORT; left->setShare(mask); left->setTravFunc(PFTRAV_CULL, CullChannel); left->setTravFunc(PFTRAV_DRAW, DrawChannel); left->setScene(scene); left->setNearFar(0.1f, far);
/* set up data to distinguish between left and right eye */ leftArg = (int *)left->allocChanData(sizeof(int)); rightArg = (int *)right->allocChanData(sizeof(int));
*leftArg = 1; *rightArg = 0;
/* data never changes, so we only need to pass it once */ left->passChanData(); right->passChanData(); left->setFOV(Fov, -1.f);
initializeFrustrum(left,right); #else pfChannel *chan = new pfChannel(pfGetPipe(0)); Shared->pw->addChan(chan); chan->setTravFunc(PFTRAV_CULL, CullChannel); chan->setTravFunc(PFTRAV_DRAW, DrawChannel); chan->setScene(scene); chan->setNearFar(near, far); // vertical FOV is matched to window aspect ratio chan->setFOV(Fov, -1.0f); #endif chan->setTravMode(PFTRAV_CULL, PFCULL_VIEW|PFCULL_GSET); if (found) { float sceneSize; // Set initial view to be "in front" of scene // view point at center of bbox Shared->view.xyz.add(bbox.min, bbox.max); Shared->view.xyz.scale(0.5f, Shared->view.xyz); // find max dimension sceneSize = bbox.max[PF_X] - bbox.min[PF_X]; sceneSize = PF_MAX2(sceneSize, bbox.max[PF_Y] - bbox.min[PF_Y]); sceneSize = PF_MAX2(sceneSize, bbox.max[PF_Z] - bbox.min[PF_Z]); sceneSize = PF_MIN2(sceneSize, 0.5f * far); Shared->sceneSize = sceneSize; // offset so all is visible Shared->view.xyz[PF_Y] -= sceneSize; Shared->view.xyz[PF_Z] += 0.25f*sceneSize; } else { Shared->view.xyz.set(0.0f, 0.0f, 100.0f); PFSET_VEC3(bbox.min, -5000.0f, -5000.0f, -1000000.0f); PFSET_VEC3(bbox.max, 5000.0f, 5000.0f, 10000000.0f); Shared->sceneSize = 10000.0f; } Shared->view.hpr.set(0.0f, 0.0f, 0.0f); chan->setView(Shared->view.xyz, Shared->view.hpr); PFCOPY_VEC3(Shared->viewOrig.xyz, Shared->view.xyz); PFCOPY_VEC3(Shared->viewOrig.hpr, Shared->view.hpr); #ifdef SPACEMOUSE Shared->smousefactor = transSpeed * Shared->sceneSize; #endif // main simulation loop while (!Shared->exitFlag) { // wait until next frame boundary pfSync(); pfFrame(); #ifdef STEREO if (frustrumChanged) initializeFrustrum(left,right); #endif // Set view parameters for next frame UpdateView(); #ifndef SPACEMOUSE chan->setView(Shared->view.xyz, Shared->view.hpr); #else mat1.makeCoord(&Shared->view); mat2.makeCoord(&Shared->spacecoord); mat1.preMult(mat2); chan->setViewMat(mat1); mat1.getOrthoCoord(&Shared->view); #endif // initiate traversal using current state if (!ForkedXInput) { if (!Shared->XInputInited) InitXInput(dsp); if (Shared->XInputInited) GetXInput(dsp); } } #ifdef SPACEMOUSE // close the Space Mouse XCloseDevice( dsp, Shared->spaceMouseDev); #endif // terminate cull and draw processes (if they exist) pfExit(); // exit to operating system return 0; }
static void InitXInput(pfWSConnection dsp) { Window w; #ifdef SPACEMOUSE initSpaceMouse(); #endif /* wait for X Window to exist in Performer shared memory */ if (w = Shared->pw->getWSWindow()) { XSelectInput(dsp, w, PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask); XMapWindow(dsp, w); XFlush(dsp); Shared->XInputInited = 1; } }
// // DoXInput() runs an asychronous forked even handling process. // Shared memory structures can be read from this process // but NO performer calls that set any structures should be // issues by routines in this process.
void DoXInput(void) { // windows from draw should now exist so can attach X input handling // to the X window Display *dsp = pfGetCurWSConnection(); prctl(PR_TERMCHILD); // Exit when parent does sigset(SIGHUP, SIG_DFL); // Exit when sent SIGHUP by TERMCHILD InitXInput(dsp); while (1) { XEvent event; if (!Shared->XInputInited) InitXInput(dsp); if (Shared->XInputInited) { XPeekEvent(dsp, &event); GetXInput(dsp); } } }
// // UpdateView() updates the eyepoint based on the information // placed in shared memory by GetInput().
static void UpdateView(void) { static float speed = 0.0f; pfCoord *view = &Shared->view; float cp; float mx, my; static double thisTime = -1.0f; double prevTime; float deltaTime;
prevTime = thisTime; thisTime = pfGetTime();
if (prevTime < 0.0f) return;
if (!Shared->inWindow || Shared->reset) { speed = 0; Shared->reset = 0; Shared->accelRate = 0.1f * Shared->sceneSize; return; }
deltaTime = thisTime - prevTime; switch (Shared->mouseButtons) { case Button1Mask: /* LEFTMOUSE: faster forward or slower backward*/ case Button1Mask|Button2Mask: speed += Shared->accelRate * deltaTime; if (speed > Shared->sceneSize) speed = Shared->sceneSize; break; case Button3Mask: /* RIGHTMOUSE: faster backward or slower foreward*/ case Button3Mask|Button2Mask: speed -= Shared->accelRate * deltaTime; if (speed < -Shared->sceneSize) speed = -Shared->sceneSize; break; } if (Shared->mouseButtons) { mx = 2.0f * (Shared->mouseX / (float)Shared->winSizeX) - 1.0f; my = 2.0f * (Shared->mouseY / (float)Shared->winSizeY) - 1.0f; /* update view direction */ view->hpr[PF_H] -= mx * PF_ABS(mx) * 30.0f * deltaTime; view->hpr[PF_P] += my * PF_ABS(my) * 30.0f * deltaTime; #ifndef SPACEMOUSE view->hpr[PF_R] = 0.0f; #endif
/* update view position */ cp = cosf(PF_DEG2RAD(view->hpr[PF_P])); view->xyz[PF_X] += speed*sinf(-PF_DEG2RAD(view->hpr[PF_H]))*cp; view->xyz[PF_Y] += speed*cosf(-PF_DEG2RAD(view->hpr[PF_H]))*cp; view->xyz[PF_Z] += speed*sinf( PF_DEG2RAD(view->hpr[PF_P])); } else { speed = 0.0f; Shared->accelRate = 0.1f * Shared->sceneSize; } }
// // CullChannel() -- traverse the scene graph and generate a // display list for the draw process. This procedure is // executed in the CULL process.
static void CullChannel(pfChannel *, void *) { // // pfDrawGeoSet or other display listable Performer routines // could be invoked before or after pfCull() pfCull(); }
// // OpenPipeWin() -- create a win: setup the GL and IRIS Performer. // This procedure is executed in the DRAW process // (when there is a separate draw process).
static void OpenPipeWin(pfPipeWindow *pw) { #ifdef STEREO pw->setFBConfigAttrs(FBAttrs); #endif pw->open(); #ifdef STEREO pw->query(PFQWIN_STEREO, &Shared->stereo); if(Shared->stereo == PFQFTR_FALSE) pfNotify(PFNFY_NOTICE, PFNFY_RESOURCE, "Couldn't get a stereo window; using mono mode"); #endif #ifdef IRISGL if (!(WinType & PFPWIN_TYPE_X)) { // register events of note with event-queue manager qdevice(ESCKEY); qdevice(F1KEY); qdevice(GKEY); } #endif // GL type // create a light source in the "south-west" (QIII) Sun = new pfLight(); Sun->setPos(-0.3f, -0.3f, 1.0f, 0.0f); }
// // DrawChannel() -- draw a channel and read input queue. this // procedure is executed in the draw process (when there is a // separate draw process).
static void DrawChannel (pfChannel *channel, void *left) { // rebind light so it stays fixed in position Sun->on(); #ifdef STEREO /* which buffer to draw into ? */ if(Shared->stereo) { /* if not stereo, draw to left all the time */ if(*(int*)left) { #ifdef IRISGL leftbuffer(1); rightbuffer(0); #else glDrawBuffer(GL_BACK_LEFT); #endif } else { #ifdef IRISGL leftbuffer(0); rightbuffer(1); #else glDrawBuffer(GL_BACK_RIGHT); #endif } } #endif /*STEREO*/ // erase framebuffer and draw Earth-Sky model channel->clear(); // invoke Performer draw-processing for this frame pfDraw(); // draw Performer throughput statistics if (Shared->drawStats) channel->drawStats(); // read window origin and size (it may have changed) channel->getPWin()->getSize(&Shared->winSizeX, &Shared->winSizeY); #ifdef IRISGL // if (!(WinType & PFPWIN_TYPE_X)) GetGLInput(); #endif // GL type #ifdef STEREO if(!Shared->stereo) /* mono mode */ if(*(int*)left) /* add extra swap to draw both buffers */ (channel->getPWin())->swapBuffers(); #endif }
#ifdef IRISGL static void GetGLInput(void) { long x, y; long xo, yo; while (qtest()) { short value; int device = qread(&value); // only act on key-down transitions if (value) { switch (device) { // ESC-key signals end of simulation case ESCKEY: Shared->exitFlag = 1; break; // g-key and F1-key toggles channel-stats display case GKEY: case F1KEY: Shared->drawStats = !Shared->drawStats; break; } } } // read cursor position (may be outside our window) x = getvaluator(MOUSEX); y = getvaluator(MOUSEY); // IRIS GL - mouse pos in screen relative and focus management is not so good // so update cursor virtual position when cursor inside window getorigin(&xo, &yo); if (x >= xo && x < (xo + Shared->winSizeX) && y >= yo && y < (yo + Shared->winSizeY)) { Shared->inWindow = 1; Shared->mouseX = x - xo; Shared->mouseY = y - yo; Shared->mouseButtons = ((getbutton(LEFTMOUSE) ? Button1Mask : 0) | (getbutton(MIDDLEMOUSE) ? Button2Mask : 0) | (getbutton(RIGHTMOUSE) ? Button3Mask : 0)); } else Shared->inWindow = 0; } #endif // GL type
static void GetXInput(pfWSConnection dsp) { static int x=0, y=0; if (XEventsQueued(dsp, QueuedAfterFlush)) while (XEventsQueued(dsp, QueuedAlready)) { XEvent event; #ifdef SPACEMOUSE XDeviceButtonEvent *ButtonPtr; XDeviceMotionEvent *MotionPtr; #endif XNextEvent(dsp, &event); switch (event.type) { case ConfigureNotify: break; case FocusIn: Shared->inWindow = 1; break; case FocusOut: Shared->inWindow = 0; break; case MotionNotify: { XMotionEvent *motion_event = (XMotionEvent *) &event; x = motion_event->x; y = Shared->winSizeY - motion_event->y; } break; case ButtonPress: { XButtonEvent *button_event = (XButtonEvent *) &event; x = event.xbutton.x; y = Shared->winSizeY - event.xbutton.y; Shared->inWindow = 1; switch (button_event->button) { case Button1: Shared->mouseButtons |= Button1Mask; break; case Button2: Shared->mouseButtons |= Button2Mask; break; case Button3: Shared->mouseButtons |= Button3Mask; break; } } break; case ButtonRelease: { XButtonEvent *button_event = (XButtonEvent *) &event; switch (button_event->button) { case Button1: Shared->mouseButtons &= ~Button1Mask; break; case Button2: Shared->mouseButtons &= ~Button2Mask; break; case Button3: Shared->mouseButtons &= ~Button3Mask; break; } } break; case KeyPress: { char buf[100]; int rv; KeySym ks; rv = XLookupString(&event.xkey, buf, sizeof(buf), &ks, 0); switch(ks) { case XK_Escape: Shared->exitFlag = 1; exit(0); break; case XK_space: Shared->reset = 1; PFCOPY_VEC3(Shared->view.xyz, Shared->viewOrig.xyz); PFCOPY_VEC3(Shared->view.hpr, Shared->viewOrig.hpr); pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "Reset"); break; case XK_g: Shared->drawStats = !Shared->drawStats; break; #ifdef STEREO case XK_KP_Add: Iod *= 1.3; frustrumChanged = TRUE; break; case XK_KP_Subtract: Iod /= 1.3; frustrumChanged = TRUE; break;
#endif default: break; } } break; default: #ifdef SPACEMOUSE if (event.type == MagellanMotionEventType){ MotionPtr = (XDeviceMotionEvent *) &(event); if ( (MotionPtr->axes_count == 6) && (MotionPtr->first_axis == 0)){ Shared->spacecoord.xyz[0]=MotionPtr->axis_data[ 0 ] *(.00002*Shared->smousefactor); Shared->spacecoord.xyz[1]=MotionPtr->axis_data[ 2 ] *(.00002*Shared->smousefactor); Shared->spacecoord.xyz[2]=MotionPtr->axis_data[ 1 ] *(.00002*Shared->smousefactor); Shared->spacecoord.hpr[0]=.001*MotionPtr->axis_data[ 4 ]; Shared->spacecoord.hpr[1]=.001*MotionPtr->axis_data[ 3 ]; Shared->spacecoord.hpr[2]=.001*MotionPtr->axis_data[ 5 ]; Shared->spacemouse=TRUE; #ifdef SPACEMOUSE_DEBUG printf("factor: %f spaceball motion: xyz: %f %f %f hpr: %f %f %f\n", Shared->smousefactor, Shared->spacecoord.xyz[0], Shared->spacecoord.xyz[1], Shared->spacecoord.xyz[2], Shared->spacecoord.hpr[0], Shared->spacecoord.hpr[1], Shared->spacecoord.hpr[2]); #endif
} } if (event.type == MagellanButtonPressEventType){ ButtonPtr = (XDeviceButtonEvent *) &(event); } if (event.type == MagellanButtonReleaseEventType){ ButtonPtr = (XDeviceButtonEvent *) &(event); } #endif break; }// switch } Shared->mouseX = x; Shared->mouseY = y; }
#ifdef SPACEMOUSE void initSpaceMouse() { int MagellanID, DeviceNumber, loop, c_class; XDeviceInfo *DeviceInfo; XDevice *Device; Window w; Display *dsp;
XAxisInfoPtr XAxisPtr; XAnyClassPtr XClassPtr; int axis, axes;
XExtensionVersion *ExtVersion;
XFeedbackState *MagellanFeedback; int FeedbackNumber;
w = Shared->pw->getWSWindow(); dsp = pfGetCurWSConnection(); ExtVersion = XGetExtensionVersion( dsp, "XInputExtension" ); if ( (ExtVersion == NULL) || ((int)ExtVersion == NoSuchExtension) ) { fprintf( stderr, "Cannot access X Input Extension. Exit ... \n"); exit( -1 ); }; printf("X Input Extension Version %d.%d \n", ExtVersion->major_version, ExtVersion->minor_version ); XFree( ExtVersion );
DeviceInfo = XListInputDevices( dsp, &DeviceNumber ); MagellanID = -1; for ( loop=0; loop<DeviceNumber; ++loop ) { printf("------------------------------------------------------------------------\n"); printf(" Type = %d \n", DeviceInfo[loop].type ); printf("Device Name = %s Type = %d Atom = %s \n", DeviceInfo[loop].name, DeviceInfo[loop].type, XGetAtomName(dsp,DeviceInfo[loop].type) ); printf(" Device Class(es) = %d Use = %s \n", DeviceInfo[loop].num_classes, DeviceInfo[loop].use ? "TRUE" : "FALSE" );
XClassPtr = (XAnyClassPtr) DeviceInfo[loop].inputclassinfo; for ( c_class=0; c_class<DeviceInfo[loop].num_classes; ++c_class ) { switch( XClassPtr->c_class ) { case 0: printf(" Keyboard Keycode Min = %d Max = %d Number of Keys = %d \n", ((XKeyInfo *)XClassPtr)->min_keycode, ((XKeyInfo *)XClassPtr)->max_keycode, ((XKeyInfo *)XClassPtr)->num_keys ); break;
case 1: printf(" Button(s) Number of Buttons = %d \n", ((XButtonInfo *)XClassPtr)->num_buttons ); break;
case 2: printf(" Valuator(s) Axes = %d Mode = %d Motion Buffer = %d \n", ((XValuatorInfo *)XClassPtr)->num_axes, ((XValuatorInfo *)XClassPtr)->mode, ((XValuatorInfo *)XClassPtr)->motion_buffer ); XAxisPtr = ((XValuatorInfo *)XClassPtr)->axes; axes = ((XValuatorInfo *)XClassPtr)->num_axes; for ( axis=0; axis<axes; ++axis ) { printf(" Valuator = %d Min = %d Max = %d Resolution = %d \n", axis+1, XAxisPtr->min_value, XAxisPtr->max_value, XAxisPtr->resolution ); ++XAxisPtr; }; break;
default: printf(" Class ID = %d Length = %d \n", XClassPtr->c_class, XClassPtr->length ); break; }; XClassPtr = (XAnyClassPtr) ((char *)XClassPtr+XClassPtr->length); }; };
for ( loop=0; loop<DeviceNumber; ++loop ) { if ( strcmp( DeviceInfo[loop].name, "MAGELLAN" ) == NULL || strcmp( DeviceInfo[loop].name, "magellan" ) == NULL ) { MagellanID = DeviceInfo[loop].id; break; }; }; if ( MagellanID == -1 ) { for ( loop=0; loop<DeviceNumber; ++loop ) { if ( strcmp( DeviceInfo[loop].name, "SPACEBALL" ) == NULL || strcmp( DeviceInfo[loop].name, "spaceball" ) == NULL ) MagellanID = DeviceInfo[loop].id; }; };
XFreeDeviceList( DeviceInfo ); printf("------------------------------------------------------------------------\n"); printf("\n\n");
if ( MagellanID == -1 ) { printf("Magellan X Input Extension. \nCan't find Magellan. Exit ... \n" ); exit( -1 ); } else printf("Magellan X Input Extension ID = %d \n", MagellanID );
Device = XOpenDevice( dsp, MagellanID ); if ( Device == 0 ) { printf("Magellan X Input Extension. \nCan't open Magellan. Exit ... \n" ); exit( -1 ); }; Shared->spaceMouseDev = Device; DeviceMotionNotify( Device, MagellanMotionEventType, MagellanMotionEventClass ); DeviceButtonPress( Device, MagellanButtonPressEventType, MagellanButtonPressEventClass ); DeviceButtonRelease( Device, MagellanButtonReleaseEventType, MagellanButtonReleaseEventClass );
printf("MotionNotify Type=%d Class=%d \n", MagellanMotionEventType, MagellanMotionEventClass ); printf("ButtonPress Type=%d Class=%d \n", MagellanButtonPressEventType, MagellanButtonPressEventClass ); printf("ButtonRelease Type=%d Class=%d \n", MagellanButtonReleaseEventType, MagellanButtonReleaseEventClass );
ListOfEventClass[0] = MagellanMotionEventClass; ListOfEventClass[1] = MagellanButtonPressEventClass; ListOfEventClass[2] = MagellanButtonReleaseEventClass;
XSelectExtensionEvent( dsp, w, ListOfEventClass, 3 );
MagellanFeedback = XGetFeedbackControl( dsp, Device, &FeedbackNumber ); printf("Magellan Feedback Number = %d \n", FeedbackNumber ); for ( loop=0; loop<FeedbackNumber; ++loop ) { printf("Feedback = %d Class = %d Length = %d ID = %d \n", loop+1, MagellanFeedback->c_class, MagellanFeedback->length, MagellanFeedback->id ); switch( MagellanFeedback->c_class ) { case KbdFeedbackClass: printf(" KbdFeedbackClass Bell Volume = %d Pitch = %d Duration = %d \n", ((XKbdFeedbackState *)MagellanFeedback)->percent, ((XKbdFeedbackState *)MagellanFeedback)->pitch, ((XKbdFeedbackState *)MagellanFeedback)->duration ); break;
case BellFeedbackClass: printf(" BellFeedbackClass Bell Volume = %d Pitch = %d Duration = %d \n", ((XBellFeedbackState *)MagellanFeedback)->percent, ((XBellFeedbackState *)MagellanFeedback)->pitch, ((XBellFeedbackState *)MagellanFeedback)->duration ); break;
case PtrFeedbackClass: printf(" PtrFeedbackClass \n"); break;
case IntegerFeedbackClass: printf(" IntegerFeedbackClass \n"); break;
case StringFeedbackClass: printf(" StringFeedbackClass \n"); break;
case LedFeedbackClass: printf(" LedFeedbackClass \n"); break;
default: printf(" Unkonw FeedbackClass \n"); } MagellanFeedback = (XFeedbackState *)((char *)MagellanFeedback+MagellanFeedback->length); } Shared->spacemouse=FALSE;
} #endif #ifdef STEREO void initializeFrustrum(pfChannel *left, pfChannel *right){ pfVec3 xyzOffsets; pfVec3 hprOffsets; float fr_l, fr_r, fr_t, fr_b; float Sx = 0.5, Sy = 0.4, Dist = 1.000;
/* set up offsets for left and right channels for stereo viewing */ /* left eye */ hprOffsets.set(0.f, 0.f, 0.f); xyzOffsets.set(-Iod/2.f, 0.f, 0.f); left->setViewOffsets(xyzOffsets, hprOffsets);
/* right eye */ hprOffsets.set(0.f, 0.f, 0.f); xyzOffsets.set(Iod/2.f, 0.f, 0.f); right->setViewOffsets(xyzOffsets, hprOffsets); fr_r = (Sx-Iod)*near/(2*Dist); fr_l = -(Sx+Iod)*near/(2*Dist); fr_t = Sy*near/(2*Dist); fr_b = -fr_t; right->makePersp(fr_l,fr_r,fr_b,fr_t); left->makePersp(-fr_r,-fr_l,fr_b,fr_t); frustrumChanged = FALSE; } #endif
======================================================================= List Archives, FAQ, FTP: http://www.sgi.com/Technology/Performer/ Submissions: info-performer++at++sgi.com Admin. requests: info-performer-request++at++sgi.com
This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:55:54 PDT