Re: The use of a Spaceball with Performer

New Message Reply Date view Thread view Subject view Author view

Javier Abadia Miranda (abadia++at++sgonyx.ita.es)
Fri, 19 Sep 1997 08:45:36 +0000


Yes. I have implemented code for Spaceball 3003,
but 2003 should be similar.

There are at least 3 ways to get data from the Sball.

1. Directly opening the /dev/tty file to which the ball is
   conected and decoding received bytes to positions and
   button states. There is a file in spacetec web that describes
   the interpretation of spaceball packets.

        ftp://ftp.spacetec.com/pub/spaceball2003and3003/.../sbsdk.txt

2. Using de Xdaemon that comes with the spaceball. This is a deamon
   that reads bytes from the spaceball and translates them into
   X events of ClientMessage type. (I think that this method only
   works for Sb 3003)

3. Using SGI's XInput extension. In my opinion this is the best
   method of the three. This extension provides a set of calls
   that open, close and receive data from a number of devices,
   and one of them is the Spaceball.
   Recently it has been posted an example of 'complex.c' source
   code modified to support Magellan spacemouse.
   This code works for the Spaceball too.

I attach this code, just in case someone doesn't have it.

If you want more info, contact me. And if you do something
interesting, please let me know.

Have fun!

//
// 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
#define 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;
#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_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;
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;
     
    // 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)
{
#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);
}

//
// 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;
#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 );
  };

 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

=======================================================================
List Archives, FAQ, FTP: http://www.sgi.com/Technology/Performer/
            Submissions: info-performer++at++sgi.com
        Admin. requests: info-performer-request++at++sgi.com


New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:55:57 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.