Javier Abadia Miranda (abadia++at++sgonyx.ita.es)
Mon, 23 Feb 1998 10:59:32 +0100
I have seen a number of questions about reading Spaceball
stuff from Performer programs.
Some months ago, it was posted an example that used XInput
extension, but unfortunately, on some multiprocessing models
it didn't work.
I have fixed that bug, (it wasn't so hard)
and I post here the example modified so
that you all can use it.
It works for Spaceball 2003.
For Spaceball 3003 you will have to do without the buttons,
because XInput driver doesn't support them.
I bet this same code will work for similar devices that
have XInput driver, only changing the device id string
from "spaceball" to whatever you want.
If you find it useful, please, let me know.
Aaaadios
//
// +---------------------------------------------------------
// | modified by Javier Abadia Miranda
// +---------------------------------------------------------
// | Ingeniero en Informatica (Computer Science)
// | Instituto Tecnologico de Aragon (Zaragoza, SPAIN)
// | 23/02/98
// +---------------------------------------------------------
// | now works with Spaceball 2003, 3003 and multiprocessing
// +---------------------------------------------------------
//
// spacemouse.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
//
// 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 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
#define SPACEMOUSE
#undef STEREO
#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>
#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;
Window valid_window;
#ifdef SPACEMOUSE
int spacemouse;
pfCoord spacecoord;
float smousefactor;
#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
static float Iod = .2f;
static float Converge = .02f;
static float Fov = 45.f;
static int FBAttrs[] = {
PFFB_RGBA,
PFFB_DOUBLEBUFFER,
PFFB_STEREO,
PFFB_DEPTH_SIZE, 23,
PFFB_RED_SIZE, 1,
PFFB_STENCIL_SIZE, 1,
None,
};
#endif
//
// APP process variables
// for configuring multi-process
static int ProcSplit = PFMP_APPCULL_DRAW;
// 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;
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
//
// 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] [-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 'c': /* set convergence ratio */
Converge = 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;
pfPipe *p;
pfBox bbox;
float far = 10000.0f;
float near = .1f;
pfWSConnection dsp=NULL;
#ifdef SPACEMOUSE
pfMatrix mat1,mat2;
static double thisTime = -1.0f;
double prevTime;
float deltaTime;
#endif
#ifdef STEREO
unsigned int mask;
int *leftArg, *rightArg;
float halfNearWidth;
float eyeAngle;
pfVec3 xyzOffsets;
pfVec3 hprOffsets;
#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;
Shared->valid_window = 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
p = pfGetPipe(0);
Shared->pw = new pfPipeWindow(p);
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(p);
pfChannel *chan = left;
pfChannel *right = new pfChannel(p);
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(45.f, -1.f);
/* set up offsets for left and right channels for stereo viewing */
/* both eyes look at same spot 1/2 way between eyes at fusion distance */
eyeAngle = PF_RAD2DEG(
atanf(Iod *.5f /(Converge * (far - near) + near)));
/* left eye */
hprOffsets.set(-eyeAngle, 0.f, 0.f);
xyzOffsets.set(-Iod/2.f, 0.f, 0.f);
left->setViewOffsets(xyzOffsets, hprOffsets);
/* right eye */
hprOffsets.set(eyeAngle, 0.f, 0.f);
xyzOffsets.set(Iod/2.f, 0.f, 0.f);
right->setViewOffsets(xyzOffsets, hprOffsets);
#else
pfChannel *chan = new pfChannel(p);
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(45.0f, -1.0f);
#endif
// Create an earth/sky model that draws sky/ground/horizon
// pfEarthSky *eSky = new pfEarthSky();
// eSky->setMode(PFES_BUFFER_CLEAR, PFES_SKY_GRND);
// eSky->setAttr(PFES_GRND_HT, -10.0f);
// chan->setESky(eSky);
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();
// Set view parameters for next frame
UpdateView();
#ifndef SPACEMOUSE
chan->setView(Shared->view.xyz, Shared->view.hpr);
#else
prevTime = thisTime;
thisTime = pfGetTime();
if (prevTime > 0){
deltaTime = thisTime-prevTime;
Shared->spacecoord.xyz.scale(deltaTime,Shared->spacecoord.xyz);
Shared->spacecoord.hpr.scale(deltaTime,Shared->spacecoord.hpr);
}
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);
}
}
// 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)
{
sleep(10);
#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
// create a light source in the "south-west" (QIII)
Sun = new pfLight();
Sun->setPos(-0.3f, -0.3f, 1.0f, 0.0f);
Shared->valid_window = pw->getWSWindow();
}
//
// 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) {
glDrawBuffer(GL_BACK_LEFT);
} else {
glDrawBuffer(GL_BACK_RIGHT);
}
}
#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 STEREO
if(!Shared->stereo) /* mono mode */
if(*(int*)left) /* add extra swap to draw both buffers */
(channel->getPWin())->swapBuffers();
#endif
}
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;
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 ]
*(.001*Shared->smousefactor);
Shared->spacecoord.xyz[1]=MotionPtr->axis_data[ 2 ]
*(.001*Shared->smousefactor);
Shared->spacecoord.xyz[2]=MotionPtr->axis_data[ 1 ]
*(.001*Shared->smousefactor);
Shared->spacecoord.hpr[0]=.1*MotionPtr->axis_data[ 4 ];
Shared->spacecoord.hpr[1]=.1*MotionPtr->axis_data[ 3 ];
Shared->spacecoord.hpr[2]=.1*MotionPtr->axis_data[ 5 ];
Shared->spacemouse=TRUE;
#define SPACEMOUSE_DEBUG
#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]);
fflush(stdout);
#endif
}
}
if (event.type == MagellanButtonPressEventType){
ButtonPtr = (XDeviceButtonEvent *) &(event);
#ifdef SPACEMOUSE_DEBUG
printf("boton pulsado %d, %d\n",
ButtonPtr->button,
ButtonPtr->state);
fflush(stdout);
#endif
}
if (event.type == MagellanButtonReleaseEventType){
ButtonPtr = (XDeviceButtonEvent *) &(event);
#ifdef SPACEMOUSE_DEBUG
printf("boton soltado %d, %d\n",
ButtonPtr->button,
ButtonPtr->state);
fflush(stdout);
#endif
}
#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;
#define WAIT_FOR_WINDOW_TO_BE_OPENED
#ifdef WAIT_FOR_WINDOW_TO_BE_OPENED
while(! Shared->valid_window)
sleep(3);
#endif
w = Shared->valid_window;
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 );
};
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
#!smake -J 1
#-------------------------------------------------------------------#
#-- Makefile for "perfly" the basic demonstration program --#
#-------------------------------------------------------------------#
#-- RCS version information --#
#-- $Revision: 1.47 $ --#
#-- $Date: 1995/12/02 07:45:30 $ --#
#-------------------------------------------------------------------#
#--
#-- definitions
#--
#-- provide a list of alternate locations for file searches
UNIQUE = ..
COMMON =
#-- alternate locatins for included files
LINCS = \
-I${UNIQUE} \
-I${COMMON}
LCINCS = $(LINCS)
#if !defined(PFSTYLE)
PFSTYLE = 32
#endif
#if $(PFSTYLE) == "64"
OBJECT_STYLE = 64
LIBBITSUF=64
PFRELEASE=N64
PFOBJECT=-DPFIRIX6
#endif
#if $(PFSTYLE) == "N32"
OBJECT_STYLE = N32_M3
LIBBITSUF=32
PFRELEASE=N32
PFOBJECT=-DPFIRIX6
#endif
#if $(PFSTYLE) == "32"
OBJECT_STYLE = 32
LIBBITSUF=
PFRELEASE=O32
PFOBJECT=-DPFIRIX5
#endif
include $(ROOT)/usr/include/make/commondefs
LIBOGL = -ignore_unresolved -lGLU -lGL -lXext -lXm -lGLw -lXi
SYSTEM_OPENGL = \
-limage \
-lfm \
${LIBOGL} \
-lXmu \
-lX11 \
-lfpe \
-lm \
-lmalloc \
-lC
#if $(PFSTYLE) == "64"
SYSTEM_OPENGL = \
-limage \
${LIBOGL} \
-lXmu \
-lX11 \
-lm \
-lC
#endif
#if $(PFSTYLE) == "N32"
SYSTEM_OPENGL = \
-limage \
${LIBOGL} \
-lXmu \
-lX11 \
-lm \
-lC
#endif
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)
OGLLIB = -lpf_ogl -lpfdu_ogl -lpfutil_ogl -lpfui
#if defined(PFSTATIC_CONVERTERS)
OGLLIB += -all $(PFSTATIC_CONVERTERS) -none
#endif
#-- base name of program
TARGET = spacemouse
#-- object files from which target built {some are in the common directory}
OBJECTS = \
spacemouse.o
#-- the debug version is in DBG and both opt and dso are in OPT
DIRS = DBG OPT
#--
#-- generic targets
#--
#-- make optimized dso version of program by default
default: ogldso
#-- make all versions of program
all: ogldbg oglopt ogldso oglddso
#-- clean up directories {remove junk}
clean:
if test -d DBG.$(PFRELEASE).OPENGL; then cd DBG.$(PFRELEASE).OPENGL ; 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).OPENGL ; then rm -rf OPT.$(PFRELEASE).OPENGL ; fi
if test -d DBG.$(PFRELEASE).OPENGL ; then rm -rf DBG.$(PFRELEASE).OPENGL ; fi
rm -f ${TARGET}
#--
#-- library targets
#--
#-- make a debugging version of the program
ogldbg: .MAKE
++at++ echo "\nmaking OpenGL DBG version of ${TARGET}"
++at++ if test ! -d DBG.$(PFRELEASE).OPENGL ; then mkdir -p DBG.$(PFRELEASE).OPENGL ; fi
++at++ cd DBG.$(PFRELEASE).OPENGL ; \
${MAKE} -f ../Makefile OPTIMIZER="-g"\
"LCDEFS=$(PFOBJECT)" "LCXXDEFS=$(PFOBJECT)"\
LIBRARIES='$(OGLLIB) -Wl,-none ${SYSTEM_OPENGL}' \
${TARGET}.DBG
++at++ rm -f ${TARGET}
ln -s DBG.$(PFRELEASE).OPENGL/${TARGET}.DBG ${TARGET}
#-- make an optimized version of the program
oglopt: .MAKE
++at++ echo "making OpenGL OPT version of ${TARGET}"
++at++ if test ! -d OPT.$(PFRELEASE).OPENGL ; then mkdir -p OPT.$(PFRELEASE).OPENGL ; fi
++at++ cd OPT.$(PFRELEASE).OPENGL ; ${MAKE} -f ../Makefile OPTIMIZER="-O " \
"LCDEFS=$(PFOBJECT)" "LCXXDEFS=$(PFOBJECT)"\
LIBRARIES='$(OGLLIB) -Wl,-none ${SYSTEM_OPENGL}' \
${TARGET}.OPT
++at++ rm -f ${TARGET}
ln -s OPT.$(PFRELEASE).OPENGL/${TARGET}.OPT ${TARGET}
#-- make an optimized version of the program that uses DSOs
ogldso: .MAKE
++at++ echo "making OpenGL DSO version of ${TARGET}"
++at++ if test ! -d OPT.$(PFRELEASE).OPENGL ; then mkdir -p OPT.$(PFRELEASE).OPENGL ; fi
++at++ cd OPT.$(PFRELEASE).OPENGL ; ${MAKE} -f ../Makefile OPTIMIZER="-O " \
"LCDEFS=$(PFOBJECT)" "LCXXDEFS=$(PFOBJECT)"\
LIBRARIES='$(OGLLIB) -Wl,-none ${SYSTEM_OPENGL}' \
${TARGET}.DSO
++at++ rm -f ${TARGET}
ln -s OPT.$(PFRELEASE).OPENGL/${TARGET}.DSO ${TARGET}
#-- make an optimized version of the program that uses DSOs
oglddso: .MAKE
++at++ echo "making OpenGL DDSO version of ${TARGET}"
++at++ if test ! -d DBG.$(PFRELEASE).OPENGL ; then mkdir -p DBG.$(PFRELEASE).OPENGL ; fi
++at++ cd DBG.$(PFRELEASE).OPENGL ; ${MAKE} -f ../Makefile OPTIMIZER="-g" \
"LCDEFS=$(PFOBJECT)" "LCXXDEFS=$(PFOBJECT)"\
LIBRARIES='$(OGLLIB) -Wl,-none ${SYSTEM_OPENGL}' \
${TARGET}.DDSO
++at++ rm -f ${TARGET}
ln -s DBG.$(PFRELEASE).OPENGL/${TARGET}.DDSO ${TARGET}
dbg: ogldbg
opt: oglopt
dso: ogldso
ddso: oglddso
#--
#-- internal targets
#--
${TARGET}.DBG: ${OBJECTS}
${CC} ${CFLAGS} -o $++at++ ${OBJECTS} $(DBGLINKS) -all ${LIBRARIES}
${TARGET}.OPT: ${OBJECTS}
${CC} ${CFLAGS} -o $++at++ ${OBJECTS} $(OPTLINKS) -all ${LIBRARIES}
${TARGET}.DSO: ${OBJECTS}
${CC} ${CFLAGS} -o $++at++ ${OBJECTS} $(DSOLINKS) -all ${LIBRARIES}
${TARGET}.DDSO: ${OBJECTS}
${CC} ${CFLAGS} -o $++at++ ${OBJECTS} $(DDSOLINKS) -all ${LIBRARIES}
#-- objects are built from either unique or common files
.PATH: ${UNIQUE} ${COMMON}
=======================================================================
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:56:51 PDT