/* * 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. * * motif.c * * IRIS Performer example using X and motif. * $Revision: 1.50 $ * $Date: 1995/12/01 23:31:25 $ * * Run-time controls: * ESC-key: exits * F1-key: profile * Left-mouse: advance * Middle-mouse: stop * Right-mouse: retreat */ #include #include #include #include #include /* for cmdline handler */ #include #include #include #include /* various Motif widget headers */ #include #include #include #include #include #include #include #include #ifdef IRISGL #include /* header for GLX Motif widget */ #else /* OPENGL */ #include /* header for OpenGL Motif widget */ #endif /* GL type */ #include #include #include #include #define HISPEED 0.1f #define LOSPEED 0.001f #define FARCLIP 10000.0f /* used in input process for X mouse tracking */ static int the_X_y_max; #define X_to_GL_Y(y) (the_X_y_max - (y)) /* * structure that resides in shared memory so that the * application, cull, and draw processes can access it. */ typedef struct { pfPipeWindow *pw; pfChannel *chan; pfScene *scene; pfNode *model; int exitFlag; int inWindow, reset; float mouseX; float mouseY; int winSizeX, winSizeY; int mouseButtons; pfCoord view, viewOrig; float sceneSize; int drawStats; int loadNewModel; char loadFileName[PF_MAXSTRING]; char loadFilePath[PF_MAXSTRING]; } SharedData; typedef struct MotifData_t { XVisualInfo *vi; Window xWin, gXWin; int *config; XtWorkProcId work_id; }MotifData_t; /* Inter-process communication structures */ static SharedData *Shared; MotifData_t *Motif; /* for configuring multi-process */ static int ProcSplit = PFMP_APPCULLDRAW; static int WriteScene = 0; /* use pfDebugPrint to write out scene upon read */ static int ForkMotif = 0; /* put Motif in a forked process */ static int WinOrgX=0, WinOrgY=0, WinSizeX=300, WinSizeY=300; char ProgName[PF_MAXSTRING]; static void CullChannel(pfChannel *chan, void *data); static void DrawChannel(pfChannel *chan, void *data); static void OpenPipeWin(pfPipeWindow *pw); static void InitPipe(void); static int SimFrame(void); static void UpdateView(void); static void LoadModel(char *filename); static void Usage(void); /* Motif process routines */ static void DoMotif(int argc, char **argv, int forked); static int WorkProc(void); static void InitMotifWidget(Widget w, XtPointer data, #ifdef IRISGL GlxDrawCallbackStruct * cb); #else /* OPENGL */ GLwDrawingAreaCallbackStruct * cb); #endif /* GL type */ static void GetTopInput(Widget w, void *call, XEvent * event); static void GetInput(Widget w, void *call, XEvent * eventp); static void quitCB(Widget w, XtPointer data, XtPointer callData); static void colorCB(Widget w, XtPointer data, XtPointer callData); static void openCB(Widget foo, XtPointer data, XtPointer callData); /* * 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 [-f][-p procSplit][-w][-W ox,oy,sx,sy] [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, "Fm:p:wW:?")) != -1) { switch (opt) { case 'F': ForkMotif ^= 1; break; case 'm': case 'p': ProcSplit = atoi(optarg); break; case 'w': WriteScene = 1; break; /* Set the window size */ case 'W': if (sscanf(optarg, "%d,%d,%d,%d", &WinOrgX, &WinOrgY, &WinSizeX, &WinSizeY) != 4) if (sscanf(optarg, "%d,%d", &WinSizeX, &WinSizeY) != 2) if (sscanf(optarg, "%d", &WinSizeX) == 1) WinSizeY = WinSizeX; break; case '?': Usage(); } } return optind; } /* * main() -- program entry point. this procedure * is executed in the application process. */ int main (int argc, char *argv[]) { int i; int arg; pfNode *root; pfPipe *p; pfEarthSky *eSky; pfLightSource *sun; pfVec3 where; pid_t fpid = 0; /* process command line arguments */ arg = docmdline(argc, argv); /* Performer Initialization */ pfInit(); /* * Allocate Shared before fork()'ing motif so that all * processes see the Shared pointer. */ Shared = (SharedData*)pfMalloc(sizeof(SharedData), pfGetSharedArena()); Shared->inWindow = 0; Shared->reset = 1; Shared->exitFlag = 0; Shared->drawStats = 1; Shared->loadNewModel = 0; pfSetVec3(Shared->view.xyz, 0.0f, -100.0f, 50.0f); pfSetVec3(Shared->view.hpr, 0.0f, 0.0f, 0.0f); /* * Set global application configuration parameters */ /* configure multi-process selection */ pfMultiprocess(ProcSplit); /* initialize the file-loader DSO before forking in pfConfig() */ if (arg < argc) pfdInitConverter(argv[arg]); /* initiate multi-processing */ pfConfig(); /* * Set off motif AFTER pfConfig so that we will have query * access to Performer objects in shared memory */ Motif = (MotifData_t*) pfCalloc(1, sizeof(MotifData_t), pfGetSharedArena()); if (ForkMotif) { if ((fpid = fork()) < 0) pfNotify(PFNFY_FATAL, PFNFY_SYSERR, "Fork of motif process failed."); else if (fpid) pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "Motif running in forked process %d", fpid); if (!fpid) DoMotif(argc, argv, ForkMotif); } pfFrameRate(20.0f); pfPhase(PFPHASE_FREE_RUN); /* * Load the initial database */ /* 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", pfGetFilePath()); /* initialize the scene graph */ Shared->scene = pfNewScene(); /* add infinite light source to scene */ sun = pfNewLSource(); pfSetVec3(where, -1.0f, -1.0f, 2.0f); pfNormalizeVec3(where); pfLSourcePos(sun, where[0], where[1], where[2], 0.0f); pfLSourceColor(sun, PFLT_DIFFUSE, 1.0f, 1.0f, 1.0f); pfAddChild(Shared->scene, sun); /* add place holder "model" to scene */ Shared->model = (pfNode *)pfNewGroup(); pfAddChild(Shared->scene, Shared->model); /* load file named on command line */ if (arg < argc) LoadModel(argv[arg]); /* Write out nodes in scene (for debugging) */ if (WriteScene) { FILE *fp; if (fp = fopen("scene.out", "w")) { pfPrint(Shared->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."); } /* * Create Pipes, Windows, and Channels */ /* Create Performer Window */ p = pfGetPipe(0); Shared->pw = pfNewPWin(p); pfPWinType(Shared->pw, PFPWIN_TYPE_X); pfPWinName(Shared->pw, "IRIS Performer"); /* set the window initialization callback */ pfPWinConfigFunc(Shared->pw, OpenPipeWin); /* set the request for the configuration of the window */ pfConfigPWin(Shared->pw); Shared->chan = pfNewChan(p); pfAddChan(Shared->pw, Shared->chan); pfChanTravMode(Shared->chan, PFTRAV_CULL, PFCULL_VIEW | PFCULL_GSET); pfChanTravFunc(Shared->chan, PFTRAV_CULL, CullChannel); pfChanTravFunc(Shared->chan, PFTRAV_DRAW, DrawChannel); pfChanScene(Shared->chan, Shared->scene); pfChanNearFar(Shared->chan, 0.1f, FARCLIP); /* Create an earth/sky model that draws sky/ground/horizon */ eSky = pfNewESky(); pfESkyMode(eSky, PFES_BUFFER_CLEAR, PFES_SKY_GRND); pfESkyAttr(eSky, PFES_GRND_HT, -100.0f); pfChanESky(Shared->chan, eSky); /* horizontal FOV is matched to window aspect ratio */ pfChanFOV(Shared->chan, 0.0f, 45.0f); /* initialize viewpoint */ pfChanView(Shared->chan, Shared->view.xyz, Shared->view.hpr); PFCOPY_VEC3(Shared->viewOrig.xyz, Shared->view.xyz); PFCOPY_VEC3(Shared->viewOrig.hpr, Shared->view.hpr); /* * Main simulation loop */ /* if Motif is forked, we control the app main loop */ if (ForkMotif) { /* wait for Motif process to initialize the pfPipeWindow parameters */ while (!Motif->xWin) sginap(1); InitPipe(); /* main simulation loop */ while (!Shared->exitFlag) SimFrame(); } else DoMotif(argc, argv, ForkMotif); /* terminate cull and draw processes (if they exist) */ pfExit(); /* exit to operating system */ exit(0); } /* * LoadModel() -- Load in new databases - * is executed in the application process. */ static void LoadModel(char *filename) { int found=0; pfBox bbox; pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "LoadModel - loading file '%s'", filename); if (pfFindFile(filename, Shared->loadFilePath, R_OK)) { pfNode *node; char *c; /* load named file */ if ((node = pfdLoadFile(Shared->loadFilePath)) != NULL) { /* install new model into scene */ pfReplaceChild(Shared->scene, Shared->model, node); pfDelete(Shared->model); Shared->model = node; found = 1; /* remove unsed objects from pfdBuilder share cache */ pfdCleanBldrShare(); /* optimize model (optional) */ #define OPTIMIZE_MODEL #ifdef OPTIMIZE_MODEL /* optimize sharing of geostate structures within scene */ pfdMakeShared(Shared->model); /* factor common geostate elements to scene geostate */ pfdMakeSharedScene(Shared->scene); /* optimize pfLayer nodes via "DISPLACE POLYGON" */ pfdCombineLayers(Shared->model); /* optimize pfBillboard nodes via */ pfdCombineBillboards(Shared->model, 32); #endif /* update file path */ strcpy(Shared->loadFileName, filename); c = strrchr(Shared->loadFilePath, '/'); if (c) *c = '\0'; } } /* set appropriate viewing position and near/far clipplanes */ if (found) { float sceneSize; /* Set initial view to be "in front" of model */ /* determine extent of scene's geometry */ pfuTravCalcBBox(Shared->model, &bbox); /* place view point at center of bbox */ pfAddVec3(Shared->view.xyz, bbox.min, bbox.max); pfScaleVec3(Shared->view.xyz, 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 * FARCLIP); Shared->sceneSize = sceneSize; /* offset so all is visible */ Shared->view.xyz[PF_Y] -= 1.50f*sceneSize; Shared->view.xyz[PF_Z] += 0.25f*sceneSize; } #ifdef RESET_VIEWPOINT_ON_FAILED_LOAD else { pfSetVec3(Shared->view.xyz, 0.0f, -100.0f, 50.0f); PFSET_VEC3(bbox.min, -5000.0, -5000.0, -5000.0); PFSET_VEC3(bbox.max, 5000.0, 5000.0, 5000.0); Shared->sceneSize = 10000.0f; } #endif } /****************************************************************************** * Motif Routines ****************************************************************************** */ static XtAppContext appcontext; void DoMotif(int argc, char **argv, int forked) { static String app_defaults[] = { "*sgiMode: true", "*useSchemes: all", NULL, }; Widget toplevel; Widget mainw, menubar, menupane, btn, cascade, frame; Widget glwidget; Arg args[8]; XVisualInfo *vi; Display *dsp; prctl(PR_TERMCHILD); /* Exit when parent does */ sigset(SIGHUP, SIG_DFL); /* Exit when sent SIGHUP by TERMCHILD */ toplevel = XtVaAppInitialize(&appcontext, ProgName, NULL, 0, &argc, argv, app_defaults, NULL, NULL); dsp = XtDisplay(toplevel); /* Create main window and motif UI widgets */ mainw = XmCreateMainWindow(toplevel, "mainw", NULL, 0); XtManageChild(mainw); /* Menu Bar */ menubar = XmCreateMenuBar(mainw, "menubar", NULL, 0); XtManageChild(menubar); /* File Menu -> Open File Button */ menupane = XmCreatePulldownMenu(menubar, "menupane", NULL, 0); btn = XmCreatePushButton(menupane, "Open", NULL, 0); XtAddCallback(btn, XmNactivateCallback, openCB, NULL); XtManageChild(btn); /* Color Menu -> Color Button */ btn = XmCreatePushButton(menupane, "Color", NULL, 0); XtAddCallback(btn, XmNactivateCallback, colorCB, NULL); XtManageChild(btn); /* File Menu -> Quit Button */ btn = XmCreatePushButton(menupane, "Quit", NULL, 0); XtAddCallback(btn, XmNactivateCallback, quitCB, NULL); XtManageChild(btn); /* Menu Bar -> File Menu */ XtSetArg(args[0], XmNsubMenuId, menupane); cascade = XmCreateCascadeButton(menubar, "File", args, 1); XtManageChild(cascade); /* create framed drawing area for OpenGL rendering */ frame = XmCreateFrame(mainw, "frame", NULL, 0); XtManageChild(frame); /* Create the Performer rendering widget with default visual */ Motif->vi = vi = pfChooseFBConfigData((void**)&(Motif->config), dsp, -1, NULL, pfGetSharedArena()); glwidget = XtVaCreateManagedWidget("glwidget", #ifdef IRISGL glxMDrawWidgetClass, frame, GlxNglxConfig, (Motif->config), #else /* OPENGL */ glwMDrawingAreaWidgetClass, frame, GLwNvisualInfo, vi, #endif /* GL type */ XmNtopOffset, 8, XmNwidth, WinSizeX, XmNheight, WinSizeY, NULL); XtAddEventHandler(mainw, StructureNotifyMask, FALSE, (XtEventHandler)GetTopInput, 0); XtAddEventHandler(glwidget, (StructureNotifyMask | PointerMotionMask | FocusChangeMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask), FALSE, (XtEventHandler)GetInput, 0); XtAddCallback(glwidget, #ifdef IRISGL GlxNginitCallback, #else /* OPENGL */ GLwNginitCallback, #endif /* GL type */ (XtCallbackProc)InitMotifWidget, 0); XmMainWindowSetAreas(mainw, menubar, NULL, NULL, NULL, frame); XtRealizeWidget(toplevel); XSync(dsp, FALSE); /* set PipeWindow X parameters from the widget */ Motif->gXWin = XtWindow(glwidget); if (!Motif->gXWin) pfNotify(PFNFY_WARN, PFNFY_PRINT, "Motif - No GFX Window!!"); #ifdef IRISGL /* if the GLXunlink fails, GL calls had probably been made before * the Motif process was forked and internal GL state is confused. */ if (Motif->gXWin && (GLXunlink(dsp, Motif->gXWin) < 0)) pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "Motif - unlink failed!!"); XSync(dsp, FALSE); #endif /* GL type */ /* this will release the waiting application process */ Motif->xWin = XtWindow(frame); if (!forked) { Motif->work_id = XtAppAddWorkProc(appcontext, (XtWorkProc)SimFrame, 0); InitPipe(); } XtAppMainLoop(appcontext); } static void InitMotifWidget(Widget w, XtPointer data, #ifdef IRISGL GlxDrawCallbackStruct * cb) #else /* OPENGL */ GLwDrawingAreaCallbackStruct * cb) #endif /* GL type */ { Screen *scr = XtScreen(w); the_X_y_max = DisplayHeight(XtDisplay(w), XScreenNumberOfScreen(scr)); } static void GetTopInput(Widget w, void *call, XEvent * event) { static pid_t draw_pid = 0; switch (event->type) { case MapNotify: if (Motif->work_id) Motif->work_id = XtAppAddWorkProc(appcontext, (XtWorkProc)SimFrame, 0); /* Resume any stopped draw process (see below) */ if (draw_pid > 0) kill(draw_pid, SIGCONT); break; case UnmapNotify: /* If there is a separate draw process, it must be temporarily * stopped, otherwise it busy-waits. */ if (Motif->work_id) XtRemoveWorkProc(Motif->work_id); if (draw_pid == 0) { int mode = pfGetMultiprocess(); if (mode & PFMP_FORK_DRAW) draw_pid = pfGetPID(0, PFPROC_DRAW); else draw_pid = -1; } if (draw_pid > 0) kill(draw_pid, SIGSTOP); break; } } static void GetInput(Widget w, void *call, XEvent * event) { static int x=0, y=0; switch (event->type) { case ConfigureNotify: break; case MotionNotify: if (Shared->mouseButtons) { XMotionEvent *motion_event = (XMotionEvent *) event; x = motion_event->x; y = Shared->winSizeY - motion_event->y; } break; case ButtonPress: { XButtonEvent *button_event = (XButtonEvent *) event; x = button_event->x; y = Shared->winSizeY - button_event->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 MapNotify: break; case UnmapNotify: break; case FocusIn: Shared->inWindow = 1; break; case FocusOut: Shared->inWindow = 0; 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; pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "Reset"); break; case XK_g: case XK_F1: Shared->drawStats = !Shared->drawStats; break; } break; } default: break; }/* switch */ /* update cursor virtual position when cursor inside window */ Shared->mouseX = x; Shared->mouseY = y; } static void loadFileCB(Widget w, XtPointer data, XtPointer callData) { XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct*) callData; if (cbs) { char *loadfile; if (!XmStringGetLtoR(cbs->value, XmFONTLIST_DEFAULT_TAG, &loadfile)) return; strcpy(Shared->loadFileName, loadfile); XtFree(loadfile); Shared->loadNewModel = 1; } } static void openCB(Widget w, XtPointer data, XtPointer callData) { static Widget fsDialog = NULL; static XmString xStr; if (!fsDialog) { fsDialog = XmCreateFileSelectionDialog(w,"w",NULL,0); XtAddCallback(fsDialog,XmNokCallback, loadFileCB, NULL); XtAddCallback(fsDialog,XmNcancelCallback, (XtCallbackProc) XtUnmanageChild, NULL); } xStr = XmStringCreateLocalized(Shared->loadFilePath); pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "Set Directory to %s", Shared->loadFilePath); /* load file selector with directory of previously choosen file */ XtVaSetValues(fsDialog, XmNdirectory, xStr, NULL); XmStringFree(xStr); xStr = XmStringCreateLocalized(Shared->loadFileName); pfNotify(PFNFY_INFO, PFNFY_PRINT, "Set Filename to %s", Shared->loadFileName); XtVaSetValues(fsDialog, XmNdirSpec, xStr, NULL); XmStringFree(xStr); XtManageChild(fsDialog); } static void colorCB(Widget w, XtPointer data, XtPointer callData) { Widget col = SgCreateColorChooser(w, "Color Chooser", NULL, 0); XtManageChild(col); } static void quitCB(Widget w, XtPointer data, XtPointer callData) { Shared->exitFlag = 1; exit(0); } /****************************************************************************** * Application Routines ****************************************************************************** */ static void InitPipe(void) { int dsp_xsize; pfPipe *p; /* set pfPipeWindow parameters from the Motif widget */ pfPWinWSDrawable(Shared->pw, NULL, Motif->gXWin); pfPWinWSWindow(Shared->pw, NULL, Motif->xWin); #ifdef IRISGL pfPWinFBConfigData(Shared->pw, Motif->config); #endif /* GL type */ } static int SimFrame(void) { /* wait until next frame boundary */ pfSync(); /* Set view parameters. */ UpdateView(); pfChanView(Shared->chan, Shared->view.xyz, Shared->view.hpr); /* initiate traversal using current state */ pfFrame(); if (Shared->loadNewModel) { /* load named database in place of current one */ LoadModel(Shared->loadFileName); Shared->loadNewModel = 0; } /* read window origin and size (it may have changed) */ pfGetPWinSize(pfGetChanPWin(Shared->chan), &Shared->winSizeX, &Shared->winSizeY); return FALSE; /* Motif: don't remove this callback */ } /* * 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 mx, my; float cp; if (!Shared->inWindow || Shared->reset) { speed = 0; if (Shared->reset) { PFCOPY_VEC3(Shared->view.xyz, Shared->viewOrig.xyz); PFCOPY_VEC3(Shared->view.hpr, Shared->viewOrig.hpr); Shared->reset = 0; Shared->mouseButtons = 0x0; Shared->mouseX = Shared->mouseY = 0; } return; } switch (Shared->mouseButtons) { case Button1Mask: /* LEFTMOUSE: faster forward or slower backward*/ if (speed > 0.0f) speed *= 1.2f; else speed /= 1.2f; if (PF_ABSLT(speed, LOSPEED * Shared->sceneSize)) speed = LOSPEED * Shared->sceneSize; else if (speed >= HISPEED * Shared->sceneSize) speed = HISPEED * Shared->sceneSize; break; case Button2Mask: /* MIDDLEMOUSE: stop moving */ speed = 0.0f; break; case Button3Mask: /* RIGHTMOUSE: faster backward or slower foreward*/ if (speed < 0.0f) speed *= 1.2f; else speed /= 1.2f; if (PF_ABSLT(speed, LOSPEED * Shared->sceneSize)) speed = -LOSPEED * Shared->sceneSize; else if (speed <= -HISPEED * Shared->sceneSize) speed = -HISPEED * 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); view->hpr[PF_P] = my * PF_ABS(my) * 90.0f; view->hpr[PF_R] = 0.0f; /* 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])); } } /****************************************************************************** * Draw Process Routines ****************************************************************************** */ /* * 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). */ Display *Dsp=NULL; static void OpenPipeWin(pfPipeWindow *pw) { pfPipe *p; Window w; pfOpenPWin(pw); Dsp = pfGetCurWSConnection(); } /****************************************************************************** * Cull Process Routines ****************************************************************************** */ /* * 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 *channel, void *data) { /* * pfDrawGeoSet or other display listable Performer routines * could be invoked before or after pfCull() */ pfCull(); } /* * 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 *data) { /* erase framebuffer and draw Earth-Sky model */ pfClearChan(channel); /* invoke Performer draw-processing for this frame */ pfDraw(); /* draw Performer throughput statistics */ if (Shared->drawStats) pfDrawChanStats(channel); }