/* * * Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ * */ /* * Copyright (C) 1990,91 Silicon Graphics, Inc. * _______________________________________________________________________ ______________ S I L I C O N G R A P H I C S I N C . ____________ | | $Revision: 1.1.1.1 $ | | Classes : SoXtFlyViewer | | Author(s) : Alain Dumesny | ______________ S I L I C O N G R A P H I C S I N C . ____________ _______________________________________________________________________ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Defines */ enum ViewerModes { STILL_MODE, FLY_MODE, TILT_MODE, SEEK_MODE, SET_UP_MODE }; // color used in feedback #define DARK_COLOR glColor3ub(90, 90, 90) #define TEXT_COLOR glColor3ub(255, 255, 90) #define MAX_SPEED_COL glColor3ub(0, 200, 200) #define CUR_SPEED_COL glColor3ub(255, 0, 0) #define CROSS 12 // cross feedback size #define CIRCLE_RAD 15 // center circle radius #define TEXT_DX 0.05 #define TEXT_DY 0.03 #define DECOR_DX 0.15 #define MIN_SPEED 0.02 #define MAX_INC 1.5 #define TURN_SPEED .8*M_PI // radians/second #define WHEEL_DOLLY_FACTOR 0.5 // Resources for labels. typedef struct { char *flyViewer; char *fvPrefSheet; char *flyingSpeed; char *increase; char *decrease; } RES_LABELS; static RES_LABELS rl; static char *defaultLabel[]={ "Fly Viewer", "Fly Viewer Preference Sheet", "Flying speed:", " increase ", " decrease " }; //////////////////////////////////////////////////////////////////////// // // Public constructor - build the widget right now // SoXtFlyViewer::SoXtFlyViewer( Widget parent, const char *name, SbBool buildInsideParent, SoXtFullViewer::BuildFlag b, SoXtViewer::Type t) : SoXtConstrainedViewer( parent, name, buildInsideParent, b, t, FALSE) // tell base class not to build just yet // //////////////////////////////////////////////////////////////////////// { // In this case, render area is what the app wants, so buildNow = TRUE constructorCommon(TRUE); } //////////////////////////////////////////////////////////////////////// // // SoEXTENDER constructor - the subclass tells us whether to build or not // SoXtFlyViewer::SoXtFlyViewer( Widget parent, const char *name, SbBool buildInsideParent, SoXtFullViewer::BuildFlag b, SoXtViewer::Type t, SbBool buildNow) : SoXtConstrainedViewer( parent, name, buildInsideParent, b, t, FALSE) // tell base class not to build just yet // //////////////////////////////////////////////////////////////////////// { // In this case, render area may be what the app wants, // or it may want a subclass of render area. Pass along buildNow // as it was passed to us. constructorCommon(buildNow); } //////////////////////////////////////////////////////////////////////// // // Called by the constructors // // private // void SoXtFlyViewer::constructorCommon(SbBool buildNow) // //////////////////////////////////////////////////////////////////////// { // init vars mode = STILL_MODE; createdCursors = FALSE; viewerCursor = seekCursor = upCursor = 0; speedLimitFactor = 0.5; setClassName("SoXtFlyViewer"); // init animation variables animationSensor = new SoFieldSensor(SoXtFlyViewer::animationSensorCB, this); // Build the widget tree, and let SoXtComponent know about our base widget. if (buildNow) { // get resources... SoXtResource xr(getParentWidget()); if (!xr.getResource( "flyViewer", "FlyViewer", rl.flyViewer )) rl.flyViewer = defaultLabel[0]; if (!xr.getResource( "flyViewerPreferenceSheet","FlyViewerPreferenceSheet",rl.fvPrefSheet )) rl.fvPrefSheet = defaultLabel[1]; if (!xr.getResource( "flyingSpeed", "FlyingSpeed", rl.flyingSpeed )) rl.flyingSpeed = defaultLabel[2]; if (!xr.getResource( "increase", "Increase", rl.increase )) rl.increase = defaultLabel[3]; if (!xr.getResource( "decrease", "Decrease", rl.decrease )) rl.decrease = defaultLabel[4]; // assign decoration names setPopupMenuString( rl.flyViewer ); setPrefSheetString( rl.fvPrefSheet ); Widget w = buildWidget(getParentWidget()); setBaseWidget(w); } } //////////////////////////////////////////////////////////////////////// // // Destructor // // Use: public SoXtFlyViewer::~SoXtFlyViewer() // //////////////////////////////////////////////////////////////////////// { // free the viewer cursors if (getDisplay()) { Display *display = getDisplay(); if (viewerCursor) XFreeCursor(display, viewerCursor); if (seekCursor) XFreeCursor(display, seekCursor); if (upCursor) XFreeCursor(display, upCursor); } } //////////////////////////////////////////////////////////////////////// // // Description: // Call the base class and sets the correct cursors on the window // // Use: virtual public void SoXtFlyViewer::setViewing(SbBool flag) // //////////////////////////////////////////////////////////////////////// { if (flag == viewingFlag) return; // call the base class SoXtConstrainedViewer::setViewing(flag); // set the right cursor Widget w = getRenderAreaWidget(); Window window = (w != NULL) ? XtWindow(w) : 0; if (window != 0) { if (!createdCursors) defineCursors(); if (isViewing()) XDefineCursor(XtDisplay(w), window, viewerCursor); else XUndefineCursor(XtDisplay(w), window); } // erase viewer feedback if (mode != STILL_MODE) switchMode(STILL_MODE); else scheduleRedraw(); } //////////////////////////////////////////////////////////////////////// // // Description: // Enables/Disable the viewer cursor on the window. // // Use: virtual public void SoXtFlyViewer::setCursorEnabled(SbBool flag) // //////////////////////////////////////////////////////////////////////// { if (flag == cursorEnabledFlag) return; cursorEnabledFlag = flag; if (! isViewing()) return; Display *display = getDisplay(); Widget w = getRenderAreaWidget(); Window window = (w != NULL) ? XtWindow(w) : 0; if (! window) return; // now set the right cursor on the window if (flag) { if (! createdCursors) defineCursors(); switch(mode) { case STILL_MODE: case FLY_MODE: case TILT_MODE: XDefineCursor(display, window, viewerCursor); break; case SEEK_MODE: XDefineCursor(display, window, seekCursor); break; case SET_UP_MODE: XDefineCursor(display, window, upCursor); break; } } else XUndefineCursor(display, window); } //////////////////////////////////////////////////////////////////////// // // Description: // redefines this to force the camera to be perspective (since // orthographic camera don't any sense in this viewer). // // Use: virtual public void SoXtFlyViewer::setCamera(SoCamera *newCamera) // //////////////////////////////////////////////////////////////////////// { if (camera == newCamera) return; // call parent class SoXtConstrainedViewer::setCamera(newCamera); // now make sure the camera is not orthographic, else switch to // perspective. if (camera != NULL && camera->isOfType(SoOrthographicCamera::getClassTypeId())) toggleCameraType(); } //////////////////////////////////////////////////////////////////////// // // Description: // This is redefined to prevent the camera type from being changed. // // Use: virtual public void SoXtFlyViewer::setCameraType(SoType type) // //////////////////////////////////////////////////////////////////////// { #ifdef DEBUG if (! type.isDerivedFrom(SoPerspectiveCamera::getClassTypeId())) SoDebugError::post("SoXtWalkViewer::setCameraType()", "ignored - must be perspective camera"); #endif } //////////////////////////////////////////////////////////////////////// // // Description: // Call the base class and sets the correct cursors on the window // // Use: virtual public void SoXtFlyViewer::setSeekMode(SbBool flag) // //////////////////////////////////////////////////////////////////////// { if (!isViewing()) return; // call the base class SoXtConstrainedViewer::setSeekMode(flag); // set the new viewer mode if (isSeekMode()) switchMode(SEEK_MODE); else switchMode(STILL_MODE); } //////////////////////////////////////////////////////////////////////// // // Description: // Call the base class and stops any flying if any. // // Use: virtual public void SoXtFlyViewer::resetToHomePosition() // //////////////////////////////////////////////////////////////////////// { // call the base class SoXtConstrainedViewer::resetToHomePosition(); // set the new viewer mode switchMode(STILL_MODE); } //////////////////////////////////////////////////////////////////////// // // Description: // Redefine this routine to add some viewer specific stuff. // // Use: virtual protected void SoXtFlyViewer::createPrefSheet() // //////////////////////////////////////////////////////////////////////// { // create the preference sheet shell and form widget Widget shell, form; createPrefSheetShellAndForm(shell, form); // create all of the parts Widget widgetList[10]; int num = 0; createDefaultPrefSheetParts(widgetList, num, form); widgetList[num++] = createFlyPrefSheetGuts(form); layoutPartsAndMapPrefSheet(widgetList, num, form, shell); } //////////////////////////////////////////////////////////////////////// // // Description: // Brings the viewer help card (called by "?" push button) // // Use: virtual protected void SoXtFlyViewer::openViewerHelpCard() // //////////////////////////////////////////////////////////////////////// { // tell the base class to open the file for us openHelpCard("SoXtFlyViewer.help"); } //////////////////////////////////////////////////////////////////////// // // Description: // Process the given event to do viewing stuff // // Use: virtual protected void SoXtFlyViewer::processEvent(XAnyEvent *xe) // //////////////////////////////////////////////////////////////////////// { // check for leave and enter notify, in which case the viewer // temporaly stops flying and resume flying if it was flying. if (isViewing() && mode == FLY_MODE) { if (xe->type == LeaveNotify) { animationSensor->detach(); animationSensor->unschedule(); interactiveCountDec(); } else if (xe->type == EnterNotify) { animationSensor->attach(viewerRealTime); animationSensor->schedule(); prevAnimTime = viewerRealTime->getValue(); interactiveCountInc(); } } if ( processCommonEvents(xe) ) return; if (!createdCursors) { defineCursors(); Widget w = getRenderAreaWidget(); XDefineCursor(XtDisplay(w), XtWindow(w), viewerCursor); } SbVec2s raSize = getGlxSize(); XButtonEvent *be; XKeyEvent *ke; switch(xe->type) { case ButtonPress: be = (XButtonEvent *)xe; if (be->button != Button1 && be->button != Button2) break; locator[0] = be->x; locator[1] = raSize[1] - be->y; switch(mode) { case STILL_MODE: // check if both buttons are down if ((be->button == Button1 && be->state & Button2Mask) || (be->button == Button2 && be->state & Button1Mask)) break; switchMode(FLY_MODE); changeMaxStraightSpeed(be->button == Button1); speed = maxSpeed; break; case FLY_MODE: // check if both buttons are down if ((be->button == Button1 && be->state & Button2Mask) || (be->button == Button2 && be->state & Button1Mask)) switchMode(STILL_MODE); else changeMaxStraightSpeed(be->button == Button1); break; case SEEK_MODE: if (be->button == Button1) seekToPoint(locator); break; case SET_UP_MODE: if (be->button == Button1) { findUpDirection(locator); switchMode(STILL_MODE); } break; } break; case MotionNotify: locator[0] = ((XMotionEvent *)xe)->x; locator[1] = raSize[1] - ((XMotionEvent *)xe)->y; switch(mode) { case FLY_MODE: // find new max speed based on curvature calculateMaxSpeed(); break; case TILT_MODE: // reset the camera orientation camera->orientation = camStartOrientation; // rotate right/left if (locator[0] != startPos[0]) { float angle = (startPos[0] - locator[0]) / float(raSize[0]); SbRotation rot(upDirection, angle * 2 * M_PI); camera->orientation = camera->orientation.getValue() * rot; } // tilt up/down if (locator[1] != startPos[1]) { float angle = (locator[1] - startPos[1]) / float(raSize[1]); tiltCamera(angle * 2 * M_PI); } break; } break; case KeyPress: ke = (XKeyEvent *)xe; locator[0] = ke->x; locator[1] = raSize[1] - ke->y; switch ( XLookupKeysym(ke, 0) ) { case XK_u: if (isSeekMode()) setSeekMode(FALSE); switchMode( (mode == SET_UP_MODE) ? STILL_MODE : SET_UP_MODE ); break; case XK_Control_L: case XK_Control_R: if (mode == STILL_MODE || mode == FLY_MODE) { interactiveCountInc(); switchMode(TILT_MODE); } break; } break; case KeyRelease: ke = (XKeyEvent *)xe; switch ( XLookupKeysym(ke, 0) ) { case XK_Control_L: case XK_Control_R: if (mode == TILT_MODE) { switchMode(STILL_MODE); interactiveCountDec(); } break; } break; } } //////////////////////////////////////////////////////////////////////// // // Description: // switches to the specified viewer mode // // Use: private void SoXtFlyViewer::switchMode(int newMode) // //////////////////////////////////////////////////////////////////////// { if (mode == newMode) return; // assing new mode SbBool redrawNeeded = TRUE; int prevMode = mode; mode = newMode; // needed to define new cursors Widget w = getRenderAreaWidget(); Display *display = (w != NULL) ? XtDisplay(w) : NULL; Window window = (w != NULL) ? XtWindow(w) : 0; if (!createdCursors && window != 0) defineCursors(); // check the old viewer mode switch(prevMode) { case FLY_MODE: animationSensor->detach(); animationSensor->unschedule(); interactiveCountDec(); break; } // switch to new viewer mode switch(newMode) { case STILL_MODE: if (window != 0) XDefineCursor(display, window, viewerCursor); break; case FLY_MODE: animationSensor->attach(viewerRealTime); animationSensor->schedule(); prevAnimTime = viewerRealTime->getValue(); interactiveCountInc(); speed = maxSpeed = maxStraightSpeed = 0; speedLimit = sceneSize * speedLimitFactor; redrawNeeded = FALSE; // wait for sensor to fire if (window != 0) XDefineCursor(display, window, viewerCursor); break; case TILT_MODE: // save mouse and camera starting values startPos = locator; camStartOrientation = camera->orientation.getValue(); if (window != 0) XDefineCursor(display, window, viewerCursor); break; case SEEK_MODE: if (window != 0) XDefineCursor(display, window, seekCursor); break; case SET_UP_MODE: if (window != 0) XDefineCursor(display, window, upCursor); break; } if (redrawNeeded) scheduleRedraw(); } //////////////////////////////////////////////////////////////////////// // // Description: // draws viewer feedback during a render area redraw of the scene. // // Use: virtual protected void SoXtFlyViewer::actualRedraw() // //////////////////////////////////////////////////////////////////////// { // have the base class draw the scene SoXtConstrainedViewer::actualRedraw(); // now draw the viewer feedback if (isViewing() && camera != NULL) { setFeedbackOrthoProjection(getGlxSize()); drawViewerFeedback(); // now restore state restoreGLStateAfterFeedback(); } } //////////////////////////////////////////////////////////////////////// // // Description: // Draws the viewer feedback once the projection and state are set. // // Use: private void SoXtFlyViewer::drawViewerFeedback() // //////////////////////////////////////////////////////////////////////// { // // draw the current action text // SbVec2s raSize = getGlxSize(); short tx = short(raSize[0] * TEXT_DX); short ty = short(raSize[1] * TEXT_DY); glRasterPos2s(tx, ty); TEXT_COLOR; // ???alain #if 0 char str[10]; switch(mode) { case STILL_MODE: charstr("Still"); break; case TILT_MODE: charstr("Tilting"); break; case SEEK_MODE: charstr("Seeking"); break; case SET_UP_MODE: charstr("Set Up Direction"); break; case FLY_MODE: charstr("Flying "); sprintf(str, "%f", speed); charstr(str); break; } #endif // // draw the current speed feedback stuff // short x0 = short(raSize[0] * DECOR_DX); short x1 = raSize[0] / 2; short x2 = raSize[0] - x0; short y = ty + 30; glLineWidth(1); DARK_COLOR; glBegin(GL_LINES); glVertex2s(x0, y); glVertex2s(x2, y); glVertex2s(x0, y-5); glVertex2s(x0, y+5); glVertex2s(x1, y-5); glVertex2s(x1, y+5); glVertex2s(x2, y-5); glVertex2s(x2, y+5); glEnd(); #if 0 cmov2s(x0-15, y-5); charstr("-"); cmov2s(x2+10, y-5); charstr("+"); #endif if (mode == FLY_MODE) { // draw the maximum speed bar short l = short((x2-x1) * maxStraightSpeed / speedLimit); MAX_SPEED_COL; glLineWidth(5); glBegin(GL_LINES); glVertex2s(x1, y); glVertex2s(x1+l, y); glEnd(); // draw the current speed bar l = short((x2-x1) * speed / speedLimit); CUR_SPEED_COL; glLineWidth(3); glBegin(GL_LINES); glVertex2s(x1, y); glVertex2s(x1+l, y); glEnd(); } // // draw mode specific stuff // glLineWidth(1); if (mode == TILT_MODE) { // draw cross at starting point DARK_COLOR; glBegin(GL_LINES); glVertex2s(startPos[0] - CROSS, startPos[1]); glVertex2s(startPos[0] + CROSS, startPos[1]); glVertex2s(startPos[0], startPos[1] - CROSS); glVertex2s(startPos[0], startPos[1] + CROSS); glEnd(); } else { #if 0 static GLUquadricObj *quad = NULL; if (! quad) quad = gluNewQuadric(); // draw small circle at screen center DARK_COLOR; circi(raSize[0]/2, raSize[1]/2, CIRCLE_RAD); #endif } // // finally draw the small directional axis // #if 0 #define DRAW_AXIS(color, x, y, z) \ cpack(color); \ axis.setValue(x, y, z); \ bgnline(); \ v3f(center.getValue()); \ v3f(axis.getValue()); \ endline(); SbVec3f axis, center(0, 0, 0); SbVec2s pos(raSize[0]/2, raSize[1]/3); short min = (raSize[0] < raSize[1]) ? raSize[0] : raSize[1]; short size = short(min * 0.08); SbMatrix mx; mx = camera->orientation.getValue().inverse(); SbVec3f bboxDir(sceneBbox.getCenter() - camera->position.getValue()); bboxDir.normalize(); SbVec3f viewVector(-mx[2][0], -mx[2][1], -mx[2][2]); ortho(-1, 1, -1, 1, -1, 1); viewport(pos[0]-size, pos[0]+size, pos[1]-size, pos[1]+size); zbuffer(TRUE); zclear(); pushmatrix(); multmatrix((Matrix) (float *) mx); DRAW_AXIS(0x6666ff, 1, 0, 0) DRAW_AXIS(0x66ff66, 0, 1, 0) DRAW_AXIS(0xff6666, 0, 0, 1) (viewVector.dot(bboxDir) < 0) ? cpack(0x66ffff) : cpack(0xff66ff); bgnline(); v3f(center.getValue()); v3f(bboxDir.getValue()); endline(); popmatrix(); zbuffer(FALSE); #undef DRAW_AXIS #endif } //////////////////////////////////////////////////////////////////////// // // Description: // This routine is used to define cursors (can only be called after // window has been realized). // // Use: private void SoXtFlyViewer::defineCursors() // //////////////////////////////////////////////////////////////////////// { XColor foreground; Pixmap source; Display *display = getDisplay(); Drawable d = DefaultRootWindow(display); // set color foreground.red = 65535; foreground.green = foreground.blue = 0; // viewing cursor source = XCreateBitmapFromData(display, d, so_xt_viewing_bits, so_xt_viewing_width, so_xt_viewing_height); viewerCursor = XCreatePixmapCursor(display, source, source, &foreground, &foreground, so_xt_viewing_x_hot, so_xt_viewing_y_hot); XFreePixmap(display, source); // seek cursor source = XCreateBitmapFromData(display, d, so_xt_target_bits, so_xt_target_width, so_xt_target_height); seekCursor = XCreatePixmapCursor(display, source, source, &foreground, &foreground, so_xt_target_x_hot, so_xt_target_y_hot); XFreePixmap(display, source); // up direction cursor source = XCreateBitmapFromData(display, d, so_xt_normal_vec_bits, so_xt_normal_vec_width, so_xt_normal_vec_height); upCursor = XCreatePixmapCursor(display, source, source, &foreground, &foreground, so_xt_normal_vec_x_hot, so_xt_normal_vec_y_hot); XFreePixmap(display, source); createdCursors = TRUE; } //////////////////////////////////////////////////////////////////////// // // Description: // Called by the animation sensor to change the camera position // // Use: private void SoXtFlyViewer::doCameraAnimation() // //////////////////////////////////////////////////////////////////////// { if (camera == NULL) return; // // get time interval since last call // SbTime time = viewerRealTime->getValue(); float sec = float((time - prevAnimTime).getValue()); prevAnimTime = time; // make sure to have at least a delta time for the first call. if (sec == 0.0) sec = 1.0/72.0; // // turn the camera left/right using the distance^2 which gives a nice // gradual speedup. // SbVec2s raSize = getGlxSize(); float dist = (locator[0] - raSize[0]/2) / float(raSize[0]); float angle = TURN_SPEED * (dist * dist) * sec; if (angle != 0.0) { if (dist < 0) angle = -angle; SbRotation rot(upDirection, -angle); camera->orientation = camera->orientation.getValue() * rot; } // // tilt camera up/down using the distance^2 which gives a nice // gradual speedup. // dist = (locator[1] - raSize[1]/2) / float(raSize[1]); angle = TURN_SPEED * (dist * dist) * sec; if (dist < 0) angle = -angle; if (angle != 0.0) tiltCamera(angle); // // move the camera forward // float dollyDist = speed * sec; if (dollyDist > 0.0) { // get camera forward direction SbMatrix mx; mx = camera->orientation.getValue(); SbVec3f forward(-mx[2][0], -mx[2][1], -mx[2][2]); // now move camera foward by distance camera->position = camera->position.getValue() + forward * dollyDist; } // // increase the current speed if we havn't reach max speed yet // if ((speed > 0 && speed < maxSpeed) || (speed < 0 && speed > maxSpeed)) { speed *= powf(3.0, sec); // clip the value to the maxSpeed if ((speed > 0 && speed > maxSpeed) || (speed < 0 && speed < maxSpeed)) speed = maxSpeed; } } //////////////////////////////////////////////////////////////////////// // // Description: // Moves the camera forward/backward (called by thumb wheel). // // Use: virtual protected void SoXtFlyViewer::rightWheelMotion(float newVal) // //////////////////////////////////////////////////////////////////////// { float dist = (newVal - rightWheelVal) * sceneSize * viewerSpeed * WHEEL_DOLLY_FACTOR; // get camera forward direction SbMatrix mx; mx = camera->orientation.getValue(); SbVec3f forward(-mx[2][0], -mx[2][1], -mx[2][2]); // now move camera foward by distance camera->position = camera->position.getValue() + forward * dist; camera->focalDistance = camera->focalDistance.getValue() - dist; rightWheelVal = newVal; } //////////////////////////////////////////////////////////////////////// // // Description: // Increases/decreases the maximum straight speed // // Use: private void SoXtFlyViewer::changeMaxStraightSpeed(SbBool increase) // //////////////////////////////////////////////////////////////////////// { // check if we are just starting if (maxStraightSpeed == 0) maxStraightSpeed = increase ? MIN_SPEED * speedLimit : - MIN_SPEED * speedLimit; else { // find the new maxStraightSpeed if ((maxStraightSpeed > 0 && increase) || (maxStraightSpeed < 0 && !increase)) maxStraightSpeed *= MAX_INC; else maxStraightSpeed /= MAX_INC; // clip to speedLimit boundaries if (maxStraightSpeed > speedLimit) maxStraightSpeed = speedLimit; else if (maxStraightSpeed < -speedLimit) maxStraightSpeed = -speedLimit; // check if we are less than the minimum speed, in which // case we just stop flying float min = MIN_SPEED * speedLimit; if (maxStraightSpeed > -min && maxStraightSpeed < min) { switchMode(STILL_MODE); return; } } // given the new maxStraightSpeed, calculate the maxSpeed calculateMaxSpeed(); } //////////////////////////////////////////////////////////////////////// // // Description: // Calculates the maximum speed based on the mouse location relative // to the screen center and the maximum forward speed. // // Use: private void SoXtFlyViewer::calculateMaxSpeed() // //////////////////////////////////////////////////////////////////////// { // get the x and y normalized distances from screen center SbVec2s raSize = getGlxSize(); float dx = 2.0 * (locator[0] - raSize[0]/2) / float(raSize[0]); if (dx < 0.0) dx = -dx; if (dx > 1.0) dx = 1.0; float dy = 2.0 * (locator[1] - raSize[1]/2) / float(raSize[1]); if (dy < 0.0) dy = -dy; if (dy > 1.0) dy = 1.0; // assign new maxSpeed and clip the current speed if needed maxSpeed = (dx > dy) ? (1.0 - dx) * maxStraightSpeed : (1.0 - dy) * maxStraightSpeed; if ((speed > 0 && speed > maxSpeed) || (speed < 0 && speed < maxSpeed)) speed = maxSpeed; } //////////////////////////////////////////////////////////////////////// // // Description: // Creates the viewer extra pref sheet stuff // // Use: private Widget SoXtFlyViewer::createFlyPrefSheetGuts(Widget parent) // //////////////////////////////////////////////////////////////////////// { Widget widgetList[3]; Arg args[12]; int n; // create a form to hold everything together Widget form = XtCreateWidget("", xmFormWidgetClass, parent, NULL, 0); // create all the parts widgetList[0] = XtCreateWidget( rl.flyingSpeed, xmLabelGadgetClass, form, NULL, 0); n = 0; XtSetArg(args[n], XmNhighlightThickness, 0); n++; widgetList[1] = XtCreateWidget( rl.increase, xmPushButtonGadgetClass, form, args, n); widgetList[2] = XtCreateWidget( rl.decrease, xmPushButtonGadgetClass, form, args, n); XtAddCallback(widgetList[1], XmNactivateCallback, (XtCallbackProc) SoXtFlyViewer::incPrefSheetButtonCB, (XtPointer) this); XtAddCallback(widgetList[2], XmNactivateCallback, (XtCallbackProc) SoXtFlyViewer::decPrefSheetButtonCB, (XtPointer) this); // layout n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetValues(widgetList[0], args, n); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[1], XmNleftWidget, widgetList[0]); n++; XtSetArg(args[n], XmNleftOffset, 10); n++; XtSetValues(widgetList[1], args, n); XtSetArg(args[1], XmNleftWidget, widgetList[1]); XtSetValues(widgetList[2], args, n); XtManageChildren(widgetList, 3); return form; } // // redefine those generic virtual functions // const char * SoXtFlyViewer::getDefaultWidgetName() const { return "SoXtFlyViewer"; } const char * SoXtFlyViewer::getDefaultTitle() const { return rl.flyViewer; } const char * SoXtFlyViewer::getDefaultIconTitle() const { return rl.flyViewer; } // //////////////////////////////////////////////////////////////////////// // static callbacks stubs //////////////////////////////////////////////////////////////////////// // void SoXtFlyViewer::animationSensorCB(void *v, SoSensor *) { ((SoXtFlyViewer *) v)->doCameraAnimation(); } void SoXtFlyViewer::incPrefSheetButtonCB(Widget, SoXtFlyViewer *v, void *) { v->speedLimitFactor *= 2.0; v->speedLimit *= 2.0; v->maxStraightSpeed *= 2.0; } void SoXtFlyViewer::decPrefSheetButtonCB(Widget, SoXtFlyViewer *v, void *) { v->speedLimitFactor /= 2.0; v->speedLimit /= 2.0; v->maxStraightSpeed /= 2.0; }