void SketchingTool::buttonCallback(int,InputDevice::ButtonCallbackData* cbData) { /* Check if the button has just been pressed: */ if(cbData->newButtonState) { /* Activate the tool: */ active=true; /* Start a new curve: */ currentCurve=new Curve; currentCurve->lineWidth=newLineWidth; currentCurve->color=newColor; curves.push_back(currentCurve); /* Append the curve's first control point: */ Curve::ControlPoint cp; const NavTransform& invNav=getInverseNavigationTransformation(); cp.pos=lastPoint=invNav.transform(getButtonDevicePosition(0)); cp.t=getApplicationTime(); currentCurve->controlPoints.push_back(cp); } else { /* Append the final control point to the curve: */ Curve::ControlPoint cp; cp.pos=currentPoint; cp.t=getApplicationTime(); currentCurve->controlPoints.push_back(cp); /* Deactivate the tool: */ active=false; currentCurve=0; } }
void RevolverTool::display(GLContextData& contextData) const { if(getApplicationTime()<showNumbersTime) { /* Set up OpenGL state: */ glPushAttrib(GL_ENABLE_BIT|GL_LINE_BIT); glDisable(GL_LIGHTING); glLineWidth(1.0f); glColor3f(0.0f,1.0f,0.0f); glPushMatrix(); /* Draw the "revolver chambers:" */ glMultMatrix(calcHUDTransform(sourceDevice->getPosition())); Scalar chamberAngle=Scalar(2)*Math::Constants<Scalar>::pi/Scalar(factory->numChambers); Scalar angleOffset=Scalar(0); double animTime=(getApplicationTime()-(showNumbersTime-1.0))*2.0; if(animTime<1.0) angleOffset=chamberAngle*Scalar(1.0-animTime); for(int i=0;i<factory->numChambers;++i) { Scalar angle=chamberAngle*Scalar(i)+angleOffset; GLNumberRenderer::Vector pos; pos[0]=Math::sin(angle)*Scalar(getUiSize()*4.0f); pos[1]=Math::cos(angle)*Scalar(getUiSize()*4.0f); pos[2]=0.0f; numberRenderer.drawNumber(pos,(currentChamber+i)%factory->numChambers+1,contextData,0,0); } glPopMatrix(); glPopAttrib(); } }
void ButtonInputDeviceTool::frame(void) { if(isActive()&&numPressedNavButtons>0) { /* Calculate the current frame time step: */ double frameTime=getApplicationTime(); double timeStep=frameTime-lastFrameTime; lastFrameTime=frameTime; /* Update the input device transformation: */ TrackerState ts=getGrabbedDevice()->getTransformation(); if(transformationMode==TRANSLATING) { for(int i=0;i<6;++i) if(navButtonStates[i]) ts.leftMultiply(TrackerState::translate(factory->translations[i]*timeStep)); } else { Point p=ts.getOrigin(); ts.leftMultiply(TrackerState::translateToOriginFrom(p)); for(int i=0;i<6;++i) if(navButtonStates[i]) ts.leftMultiply(TrackerState::rotate(Rotation::rotateScaledAxis(factory->rotations[i]*timeStep))); ts.leftMultiply(TrackerState::translateFromOriginTo(p)); } getGrabbedDevice()->setTransformation(ts); /* Request another frame: */ scheduleUpdate(getApplicationTime()+1.0/125.0); } }
void RevolverTool::display(GLContextData& contextData) const { if(getApplicationTime()<showNumbersTime) { /* Get the context data item: */ DataItem* dataItem=contextData.retrieveDataItem<DataItem>(this); /* Set up OpenGL state: */ glPushAttrib(GL_ENABLE_BIT|GL_LINE_BIT); glDisable(GL_LIGHTING); glLineWidth(1.0f); glColor3f(0.0f,1.0f,0.0f); glPushMatrix(); /* Draw the "revolver chambers:" */ glMultMatrix(getDeviceTransformation(0)); Scalar chamberAngle=Scalar(2)*Math::Constants<Scalar>::pi/Scalar(factory->numButtons); Scalar angleOffset=Scalar(0); double animTime=(getApplicationTime()-(showNumbersTime-1.0))*2.0; if(animTime<1.0) angleOffset=chamberAngle*Scalar(1.0-animTime); for(int i=0;i<factory->numButtons;++i) { Scalar angle=chamberAngle*Scalar(i)+angleOffset; Point position(Math::sin(angle)*Scalar(getUiSize()*4.0f),Scalar(0),Math::cos(angle)*Scalar(getUiSize()*4.0f)); dataItem->writeNumber(position,(mappedButtonIndex+i)%factory->numButtons+1); } glPopMatrix(); glPopAttrib(); } }
void RevolverTool::frame(void) { /* Call the base class method: */ TransformTool::frame(); /* Request a rendering update while the animation is going: */ if(getApplicationTime()<showNumbersTime) { /* Request another frame: */ scheduleUpdate(getApplicationTime()+1.0/125.0); } }
void ComeHitherNavigationTool::frame(void) { /* Act depending on this tool's current state: */ if(isActive()) { /* Get the current application time: */ double time=getApplicationTime(); if(time>=endTime) { /* Set the final navigation transformation: */ setNavigationTransformation(targetNav); /* Deactivate this tool: */ deactivate(); } else { /* Compute and set the intermediate navigation transformation: */ double deltaTime=time-startTime; NavTransform delta=NavTransform(linearVelocity*deltaTime,Rotation::rotateScaledAxis(angularVelocity*deltaTime),Scalar(1)); delta*=startNav; setNavigationTransformation(delta); } } }
void SixAxisTransformTool::frame(void) { /* Assemble translation from translation vectors and current valuator values: */ Vector translation=Vector::zero; for(int i=0; i<3; ++i) translation+=translations[i]*Scalar(getValuatorState(i)); translation*=getCurrentFrameTime(); /* Assemble rotation from scaled rotation axes and current valuator values: */ Vector rotation=Vector::zero; for(int i=0; i<3; ++i) rotation+=config.rotations[i]*Scalar(getValuatorState(3+i)); rotation*=getCurrentFrameTime(); /* Calculate an incremental transformation for the virtual input device: */ ONTransform deltaT=ONTransform::translate(translation); Point pos=transformedDevice->getPosition(); deltaT*=ONTransform::translateFromOriginTo(pos); deltaT*=ONTransform::rotate(ONTransform::Rotation::rotateScaledAxis(rotation)); deltaT*=ONTransform::translateToOriginFrom(pos); /* Update the virtual input device's transformation: */ deltaT*=transformedDevice->getTransformation(); deltaT.renormalize(); transformedDevice->setTransformation(deltaT); /* Request another frame if the input device has moved: */ if(translation!=Vector::zero||rotation!=Vector::zero) { /* Request another frame: */ scheduleUpdate(getApplicationTime()+1.0/125.0); } }
void ScrollTool::valuatorCallback(int,InputDevice::ValuatorCallbackData* cbData) { if(cbData->newValuatorValue!=0.0) // Valuator is pushed { /* Check if the GUI interactor accepts the event: */ GUIInteractor::updateRay(); GLMotif::TextControlEvent tce(cbData->newValuatorValue>0.0?GLMotif::TextControlEvent::CURSOR_UP:GLMotif::TextControlEvent::CURSOR_DOWN); int numEvents=int(Math::ceil(Math::abs(cbData->newValuatorValue)*10.0)); sendingEvents=false; for(int i=0;i<numEvents;++i) sendingEvents=GUIInteractor::textControl(tce)||sendingEvents; if(sendingEvents) { /* Request another frame: */ scheduleUpdate(getApplicationTime()+1.0/125.0); } else { /* Pass the valuator event to the virtual input device: */ valuatorDevice->setValuator(0,cbData->newValuatorValue); } } else // Valuator has just been released { /* Check if the tool has been sending text control events: */ if(!sendingEvents) { /* Pass the button event to the virtual input device: */ valuatorDevice->setValuator(0,cbData->newValuatorValue); } sendingEvents=false; } }
void RevolverTool::buttonCallback(int buttonSlotIndex,InputDevice::ButtonCallbackData* cbData) { if(buttonSlotIndex==0) { if(cbData->newButtonState) { /* Change the currently mapped button set: */ currentChamber=(currentChamber+1)%factory->numChambers; /* Set the newly mapped chamber's state to the input device's buttons' and valuators' states: */ for(int i=1;i<input.getNumButtonSlots();++i) transformedDevice->setButtonState((i-1)*factory->numChambers+currentChamber,getButtonState(i)); for(int i=0;i<input.getNumValuatorSlots();++i) transformedDevice->setValuator(i*factory->numChambers+currentChamber,getValuatorState(i)); /* Show the current button assignment for one second: */ showNumbersTime=getApplicationTime()+1.0; } } else { /* Pass the button event through to the virtual input device: */ transformedDevice->setButtonState((buttonSlotIndex-1)*factory->numChambers+currentChamber,cbData->newButtonState); } }
ButtonInputDeviceTool::ButtonInputDeviceTool(const ToolFactory* sFactory,const ToolInputAssignment& inputAssignment) :InputDeviceTool(sFactory,inputAssignment), transformationMode(TRANSLATING), numPressedNavButtons(0), lastFrameTime(getApplicationTime()) { for(int i=0;i<6;++i) navButtonStates[i]=false; }
void RevolverTool::frame(void) { /* Call the base class method: */ TransformTool::frame(); /* Request a rendering update while the animation is going: */ if(getApplicationTime()<showNumbersTime) requestUpdate(); }
int App::run() { try{init(); m_running = GL_TRUE;} catch(std::exception &e){LOG_ERROR<<e.what();} double timeStamp = 0.0; // Main loop while( m_running ) { // update application time timeStamp = getApplicationTime(); // poll io_service if no seperate worker-threads exist if(!m_main_queue.get_num_threads()) m_main_queue.io_service().poll(); // poll input events pollEvents(); // time elapsed since last frame double time_delta = timeStamp - m_lastTimeStamp; // call update callback update(time_delta); m_lastTimeStamp = timeStamp; if(needs_redraw()) { // call draw callback draw_internal(); // Swap front and back rendering buffers swapBuffers(); } // perform fps-timing timing(timeStamp); // Check if ESC key was pressed or window was closed or whatever m_running = checkRunning(); // fps managment float current_fps = 1.f / time_delta; if(current_fps > m_max_fps) { double sleep_secs = std::max(0.0, (1.0 / m_max_fps - time_delta)); this_thread::sleep_for(duration_t(sleep_secs)); } } // manage tearDown, save stuff etc. tearDown(); return EXIT_SUCCESS; }
void InputDeviceAdapterTrackd::updateInputDevices(void) { for(int deviceIndex=0;deviceIndex<numInputDevices;++deviceIndex) { /* Get pointer to the input device: */ InputDevice* device=inputDevices[deviceIndex]; /* Don't update tracker-related state for devices that are not tracked: */ if(trackerIndexMapping[deviceIndex]>=0) { /* Get device's tracker state from sensor shared memory segment: */ SensorData& sd=*sensors[trackerIndexMapping[deviceIndex]]; /***************************************************************** Construct device's transformation: *****************************************************************/ /* Translation vector is straightforward: */ Vector translation=Vector(Scalar(sd.position[0]),Scalar(sd.position[1]),Scalar(sd.position[2])); /* To assemble the orientation, we assume all angles are in degrees, and the order of rotations is as follows: */ Rotation rotation=Rotation::rotateZ(Math::rad(Scalar(sd.angles[0]))); rotation*=Rotation::rotateX(Math::rad(Scalar(sd.angles[1]))); rotation*=Rotation::rotateY(Math::rad(Scalar(sd.angles[2]))); /* Calibrate the device's position and orientation from the trackd daemon's space to Vrui's physical space: */ OGTransform calibratedTransformation=calibrationTransformation; calibratedTransformation*=OGTransform(translation,rotation,Scalar(1)); /* Calibrate and set the device's transformation: */ device->setTransformation(TrackerState(calibratedTransformation.getTranslation(),calibratedTransformation.getRotation())); /* Set device's linear and angular velocities to zero because we don't know any better: */ device->setLinearVelocity(Vector::zero); device->setAngularVelocity(Vector::zero); } /* Update button states: */ for(int i=0;i<device->getNumButtons();++i) device->setButtonState(i,buttons[buttonIndexMapping[deviceIndex][i]]); /* Update valuator states: */ for(int i=0;i<device->getNumValuators();++i) device->setValuator(i,valuators[valuatorIndexMapping[deviceIndex][i]]); } /* Schedule the next Vrui frame at the update interval if asked to do so: */ if(updateInterval!=0.0) Vrui::scheduleUpdate(getApplicationTime()+updateInterval); }
void HelicopterNavigationTool::buttonCallback(int,int buttonIndex,InputDevice::ButtonCallbackData* cbData) { /* Process based on which button was pressed: */ if(buttonIndex==0) { if(cbData->newButtonState) { /* Act depending on this tool's current state: */ if(isActive()) { /* Go back to original transformation: */ NavTransform nav=pre; nav*=NavTransform::translateToOriginFrom(currentPosition); nav*=post; setNavigationTransformation(nav); /* Deactivate this tool: */ deactivate(); } else { /* Try activating this tool: */ if(activate()) { /* Initialize the navigation: */ Vector x=Geometry::cross(getForwardDirection(),getUpDirection()); Vector y=Geometry::cross(getUpDirection(),x); pre=NavTransform::translateFromOriginTo(getMainViewer()->getHeadPosition()); pre*=NavTransform::rotate(Rotation::fromBaseVectors(x,y)); post=Geometry::invert(pre); post*=getNavigationTransformation(); currentPosition=Point::origin; currentOrientation=Rotation::identity; currentVelocity=Vector::zero; lastFrameTime=getApplicationTime(); } } } } else { /* Store the new state of the button: */ buttons[buttonIndex-1]=cbData->newButtonState; } }
void JediTool::buttonCallback(int,InputDevice::ButtonCallbackData* cbData) { if(cbData->newButtonState) // Activation button has just been pressed { if(!active) { /* Activate the light saber: */ active=true; activationTime=getApplicationTime(); } else { /* Deactivate the light saber: */ active=false; } } }
void SixAxisNavigationTool::frame(void) { if(isActive()) { /* Assemble translation from translation vectors and current valuator values: */ Vector translation=Vector::zero; for(int i=0;i<3;++i) translation+=translations[i]*Scalar(getValuatorState(i)); translation*=getCurrentFrameTime(); /* Assemble rotation from scaled rotation axes and current valuator values: */ Vector rotation=Vector::zero; for(int i=0;i<3;++i) rotation+=rotations[i]*Scalar(getValuatorState(3+i)); rotation*=getCurrentFrameTime(); /* Calculate incremental zoom factor: */ Scalar zoom=config.zoomFactor*Scalar(getValuatorState(6))*getCurrentFrameTime(); /* Apply proper navigation mode: */ if(config.invertNavigation) { translation=-translation; rotation=-rotation; zoom=-zoom; } /* Calculate an incremental transformation based on the translation and rotation: */ NavTrackerState deltaT=NavTrackerState::translateFromOriginTo(config.followDisplayCenter?getDisplayCenter():config.navigationCenter); deltaT*=NavTrackerState::translate(translation); deltaT*=NavTrackerState::rotate(NavTrackerState::Rotation::rotateScaledAxis(rotation)); deltaT*=NavTrackerState::scale(Math::exp(-zoom)); deltaT*=NavTrackerState::translateToOriginFrom(config.followDisplayCenter?getDisplayCenter():config.navigationCenter); /* Update the accumulated transformation: */ navTransform.leftMultiply(deltaT); navTransform.renormalize(); /* Update the navigation transformation: */ setNavigationTransformation(navTransform); /* Request another frame: */ scheduleUpdate(getApplicationTime()+1.0/125.0); } }
void HelicopterNavigationTool::frame(void) { /* Act depending on this tool's current state: */ if(isActive()) { double newFrameTime=getApplicationTime(); Scalar dt=Scalar(newFrameTime-lastFrameTime); /* Update the current orientation based on the pitch, roll, and yaw controls: */ Vector rot=Vector(valuators[0]*factory->rotateFactors[0],valuators[1]*factory->rotateFactors[1],valuators[2]*factory->rotateFactors[2]); currentOrientation.leftMultiply(Rotation::rotateScaledAxis(rot*dt)); currentOrientation.renormalize(); /* Update the current velocity based on collective, throttle and brake: */ Vector accel=Vector(0,0,-factory->g); accel+=currentOrientation.inverseTransform(Vector(0,0,(factory->collectiveMax-factory->collectiveMin)*(Scalar(1)-valuators[3])*Scalar(0.5)+factory->collectiveMin)); if(buttons[0]) accel+=currentOrientation.inverseTransform(Vector(0,factory->thrust,0)); if(buttons[1]) accel+=currentOrientation.inverseTransform(Vector(0,-factory->brake,0)); /* Calculate drag: */ Vector localVel=currentOrientation.transform(currentVelocity); Vector drag=Vector(localVel[0]*factory->dragCoefficients[0],localVel[1]*factory->dragCoefficients[1],localVel[2]*factory->dragCoefficients[2]); accel+=currentOrientation.inverseTransform(drag); currentVelocity+=accel*dt; /* Update the current position based on current velocity: */ currentPosition+=currentVelocity*dt; /* Set the new navigation transformation: */ NavTransform nav=pre; nav*=NavTransform::rotate(Rotation::rotateZ(valuators[4]*factory->viewAngleFactors[0])); nav*=NavTransform::rotate(Rotation::rotateX(valuators[5]*factory->viewAngleFactors[1])); nav*=NavTransform::rotate(currentOrientation); nav*=NavTransform::translateToOriginFrom(currentPosition); nav*=post; setNavigationTransformation(nav); /* Prepare for the next frame: */ lastFrameTime=newFrameTime; Vrui::requestUpdate(); } }
void RevolverTool::buttonCallback(int,int deviceButtonIndex,InputDevice::ButtonCallbackData* cbData) { if(deviceButtonIndex==0) { /* Pass the button event through to the virtual input device: */ transformedDevice->setButtonState(mappedButtonIndex,cbData->newButtonState); } else if(cbData->newButtonState) { /* Change the currently mapped button: */ mappedButtonIndex=(mappedButtonIndex+1)%factory->numButtons; /* Set the newly mapped button's state to the input device's button's state: */ transformedDevice->setButtonState(mappedButtonIndex,getDeviceButtonState(0,0)); /* Show the current button assignment: */ showNumbersTime=getApplicationTime()+1.0; } }
void JediTool::frame(void) { if(active) { /* Update the light saber billboard: */ origin=getButtonDevicePosition(0); axis=getButtonDeviceRayDirection(0); /* Scale the lightsaber during activation: */ length=factory->lightsaberLength; double activeTime=getApplicationTime()-activationTime; if(activeTime<1.5) { length*=activeTime/1.5; /* Request another frame: */ scheduleUpdate(getNextAnimationTime()); } } }
void ViewpointFileNavigationTool::frame(void) { /* Animate the navigation transformation if the tool is active: */ if(isActive()) { /* Get the next curve parameter: */ Scalar newParameter=parameter+Scalar(getFrameTime())*speed; /* Check if a pause was scheduled between the last frame and this one: */ bool passedPause=false; for(std::vector<Scalar>::const_iterator pIt=pauses.begin();pIt!=pauses.end();++pIt) if(parameter<*pIt&&*pIt<=newParameter) { passedPause=true; newParameter=*pIt; break; } /* Navigate to the new curve parameter: */ if(!navigate(newParameter)) { /* Stop animating, curve is over: */ deactivate(); } else if(passedPause) { paused=true; deactivate(); } else { /* Request another frame: */ scheduleUpdate(getApplicationTime()+1.0/125.0); } /* Update the curve parameter and the GUI: */ parameter=newParameter; if(positionSlider!=0) positionSlider->setValue(parameter); } }
void SketchingTool::frame(void) { if(active) { /* Get the current dragging point: */ const NavTransform& invNav=getInverseNavigationTransformation(); currentPoint=invNav.transform(getButtonDevicePosition(0)); /* Check if the dragging point is far enough away from the most recent curve vertex: */ if(Geometry::sqrDist(currentPoint,lastPoint)>=Math::sqr(factory->detailSize*invNav.getScaling())) { /* Append the current dragging point to the curve: */ Curve::ControlPoint cp; cp.pos=currentPoint; cp.t=getApplicationTime(); currentCurve->controlPoints.push_back(cp); /* Remember the last added point: */ lastPoint=currentPoint; } } }
void ValuatorTurnNavigationTool::frame(void) { /* Act depending on this tool's current state: */ if(isActive()) { /* Get the current state of the input device: */ const TrackerState& ts=getButtonDeviceTransformation(0); /* Calculate the current flying velocity: */ Vector v=Vector::zero; if(buttonState) { v=ts.transform(factory->flyDirection); v*=-factory->flyFactor*getFrameTime(); } /* Calculate the current angular velocities: */ Vector w0=factory->rotationAxis0; w0*=currentValues[0]*factory->rotationFactor*getFrameTime(); Vector w1=factory->rotationAxis1; w1*=currentValues[1]*factory->rotationFactor*getFrameTime(); /* Compose the new navigation transformation: */ Point p=ts.transform(factory->rotationCenter); NavTransform t=NavTransform::translate(v); t*=NavTransform::translateFromOriginTo(p); t*=NavTransform::rotate(NavTransform::Rotation::rotateScaledAxis(w0)); t*=NavTransform::rotate(NavTransform::Rotation::rotateScaledAxis(w1)); t*=NavTransform::translateToOriginFrom(p); t*=getNavigationTransformation(); /* Update Vrui's navigation transformation: */ setNavigationTransformation(t); /* Request another frame: */ scheduleUpdate(getApplicationTime()+1.0/125.0); } }
void ValuatorFlyNavigationTool::frame(void) { /* Act depending on this tool's current state: */ if(isActive()) { /* Get the current state of the input device: */ const TrackerState& ts=getValuatorDeviceTransformation(0); /* Calculate the current flying velocity: */ Vector v=ts.transform(factory->flyDirection); v*=-currentValue*factory->flyFactor*getFrameTime(); /* Compose the new navigation transformation: */ NavTransform t=NavTransform::translate(v); t*=getNavigationTransformation(); /* Update Vrui's navigation transformation: */ setNavigationTransformation(t); /* Request another frame: */ scheduleUpdate(getApplicationTime()+1.0/125.0); } }
void ButtonInputDeviceTool::buttonCallback(int buttonSlotIndex,InputDevice::ButtonCallbackData* cbData) { if(cbData->newButtonState) // Button has just been pressed { switch(buttonSlotIndex) { case 0: // Device switch button grabNextDevice(); break; case 1: // Transformation mode toggle if(transformationMode==TRANSLATING) transformationMode=ROTATING; else transformationMode=TRANSLATING; break; case 2: // Navigation buttons case 3: case 4: case 5: case 6: case 7: if(!navButtonStates[buttonSlotIndex-2]) { navButtonStates[buttonSlotIndex-2]=true; if(numPressedNavButtons==0) lastFrameTime=getApplicationTime(); ++numPressedNavButtons; } break; default: // Forwarded buttons /* Let input device tool handle it: */ InputDeviceTool::buttonCallback(buttonSlotIndex,cbData); } } else // Button has just been released { switch(buttonSlotIndex) { case 0: // Device switch button case 1: // Transformation mode toggle break; case 2: // Navigation buttons case 3: case 4: case 5: case 6: case 7: if(navButtonStates[buttonSlotIndex-2]) { navButtonStates[buttonSlotIndex-2]=false; --numPressedNavButtons; } break; default: // Forwarded buttons /* Let input device tool handle it: */ InputDeviceTool::buttonCallback(buttonSlotIndex,cbData); } } }
void MouseDialogNavigationTool::buttonCallback(int,InputDevice::ButtonCallbackData* cbData) { if(cbData->newButtonState) // Button has just been pressed { bool takeEvent=true; if(factory->interactWithWidgets) { /* Check if the GUI interactor accepts the event: */ GUIInteractor::updateRay(); if(GUIInteractor::buttonDown(false)) { /* Deactivate this tool if it is spinning: */ if(spinning) deactivate(); spinning=false; /* Disable navigation: */ takeEvent=false; } } if(takeEvent) { /* Deactivate spinning: */ spinning=false; /* Start navigating according to the current navigation mode: */ switch(navigationMode) { case ROTATING: if(activate()) startRotating(); break; case PANNING: if(activate()) startPanning(); break; case DOLLYING: if(activate()) startDollying(); break; case SCALING: if(activate()) startScaling(); break; } } } else // Button has just been released { if(GUIInteractor::isActive()) { /* Deliver the event: */ GUIInteractor::buttonUp(); } else { /* Check for spinning if currently in rotating mode: */ if(navigationMode==ROTATING) { /* Check if the input device is still moving: */ Point currentPos=calcScreenPos(); Vector delta=currentPos-lastRotationPos; if(Geometry::mag(delta)>factory->spinThreshold) { /* Calculate spinning angular velocity: */ Vector offset=(lastRotationPos-screenCenter)+rotateOffset; Vector axis=Geometry::cross(offset,delta); Scalar angularVelocity=Geometry::mag(delta)/(factory->rotateFactor*(getApplicationTime()-lastMoveTime)); spinAngularVelocity=axis*(Scalar(0.5)*angularVelocity/axis.mag()); /* Enable spinning: */ spinning=true; } else { /* Deactivate the tool: */ deactivate(); } } else { /* Deactivate the tool: */ deactivate(); } } } }
void SixAxisSurfaceNavigationTool::frame(void) { /* Act depending on this tool's current state: */ if(isActive()) { /* Use the average frame time as simulation time: */ Scalar dt=getCurrentFrameTime(); /* Update rotation angles based on current rotation valuator states: */ for(int i=0;i<3;++i) angles[i]=wrapAngle(angles[i]+getValuatorState(i+3)*factory->rotateFactors[i]*dt); if(angles[1]<Math::rad(Scalar(-90))) angles[1]=Math::rad(Scalar(-90)); else if(angles[1]>Math::rad(Scalar(90))) angles[1]=Math::rad(Scalar(90)); if(!factory->canRoll||factory->bankTurns) { Scalar targetRoll=factory->bankTurns?getValuatorState(3)*factory->rotateFactors[2]:Scalar(0); Scalar t=Math::exp(-factory->levelSpeed*dt); angles[2]=angles[2]*t+targetRoll*(Scalar(1)-t); if(Math::abs(angles[2]-targetRoll)<Scalar(1.0e-3)) angles[2]=targetRoll; } /* Calculate the new head position: */ Point newHeadPos=getMainViewer()->getHeadPosition(); /* Create a physical navigation frame around the new foot position: */ calcPhysicalFrame(newHeadPos); /* Calculate movement from head position change: */ Vector move=newHeadPos-headPos; headPos=newHeadPos; /* Add movement velocity based on the current translation valuator states: */ for(int i=0;i<3;++i) move[i]+=getValuatorState(i)*factory->translateFactors[i]*dt; /* Transform the movement vector from physical space to the physical navigation frame: */ move=physicalFrame.inverseTransform(move); /* Rotate by the current azimuth and elevation angles: */ move=Rotation::rotateX(-angles[1]).transform(move); move=Rotation::rotateZ(-angles[0]).transform(move); /* Move the surface frame: */ NavTransform newSurfaceFrame=surfaceFrame; newSurfaceFrame*=NavTransform::translate(move); /* Re-align the surface frame with the surface: */ Point initialOrigin=newSurfaceFrame.getOrigin(); Rotation initialOrientation=newSurfaceFrame.getRotation(); AlignmentData ad(surfaceFrame,newSurfaceFrame,factory->probeSize,factory->maxClimb); align(ad); if(!factory->fixAzimuth) { /* Have the azimuth angle track changes in the surface frame's rotation: */ Rotation rot=Geometry::invert(initialOrientation)*newSurfaceFrame.getRotation(); rot.leftMultiply(Rotation::rotateFromTo(rot.getDirection(2),Vector(0,0,1))); Vector x=rot.getDirection(0); angles[0]=wrapAngle(angles[0]+Math::atan2(x[1],x[0])); } /* If flying is allowed and the initial surface frame was above the surface, lift it back up: */ Scalar z=newSurfaceFrame.inverseTransform(initialOrigin)[2]; if(!factory->canFly||z<factory->probeSize) z=factory->probeSize; newSurfaceFrame*=NavTransform::translate(Vector(Scalar(0),Scalar(0),z)); /* Apply the newly aligned surface frame: */ surfaceFrame=newSurfaceFrame; applyNavState(); /* Deactivate the tool if it is done: */ if(numActiveAxes==0&&Math::abs(angles[2])<Math::Constants<Scalar>::epsilon) deactivate(); else { /* Request another frame: */ scheduleUpdate(getApplicationTime()+1.0/125.0); } } }
void ComeHitherNavigationTool::buttonCallback(int,int,InputDevice::ButtonCallbackData* cbData) { if(cbData->newButtonState) // Button has just been pressed { if(isActive()) // Tool is already active { /* Snap to the target transformation immediately: */ setNavigationTransformation(targetNav); /* Deactivate this tool: */ deactivate(); } else // Tool is not yet active { /* Try activating this tool: */ if(activate()) { /* Get the start navigation transformation: */ startNav=getNavigationTransformation(); startTime=getApplicationTime(); /* Get the target transformation: */ NavTransform device=getDeviceTransformation(0); device.leftMultiply(getInverseNavigationTransformation()); Point center=device.getOrigin(); Vector forward=device.getDirection(1); Vector up=device.getDirection(2); /* Compute the navigation transformation for the target transformation: */ targetNav=NavTransform::identity; targetNav*=NavTransform::translateFromOriginTo(getDisplayCenter()); targetNav*=NavTransform::rotate(Rotation::fromBaseVectors(Geometry::cross(getForwardDirection(),getUpDirection()),getForwardDirection())); targetNav*=NavTransform::scale(startNav.getScaling()); targetNav*=NavTransform::rotate(Geometry::invert(Rotation::fromBaseVectors(Geometry::cross(forward,up),forward))); targetNav*=NavTransform::translateToOriginFrom(center); /* Compute the linear and angular velocities for the movement: */ NavTransform delta=startNav; delta.doInvert(); delta.leftMultiply(targetNav); Vector linearDist=delta.getTranslation(); double linearMag=Geometry::mag(linearDist); Vector angularDist=delta.getRotation().getScaledAxis(); double angularMag=Geometry::mag(angularDist); if(linearMag<=factory->linearSnapThreshold&&angularMag<=factory->angularSnapThreshold) { /* Snap to the target transformation immediately: */ setNavigationTransformation(targetNav); /* Deactivate this tool: */ deactivate(); } else { /* Compute the total transition time: */ double transitionTime=linearMag/factory->maxLinearVelocity; if(transitionTime<angularMag/factory->maxAngularVelocity) transitionTime=angularMag/factory->maxAngularVelocity; endTime=startTime+transitionTime; /* Compute the effective linear and angular velocities: */ linearVelocity=linearDist/Scalar(transitionTime); angularVelocity=angularDist/Scalar(transitionTime); } } } } }
void MouseNavigationTool::buttonCallback(int buttonSlotIndex,InputDevice::ButtonCallbackData* cbData) { /* Process based on which button was pressed: */ switch(buttonSlotIndex) { case 0: if(cbData->newButtonState) // Button has just been pressed { /* Act depending on this tool's current state: */ switch(navigationMode) { case IDLE: case SPINNING: if(factory->interactWithWidgets) { /* Check if the GUI interactor accepts the event: */ GUIInteractor::updateRay(); if(GUIInteractor::buttonDown(false)) { /* Deactivate this tool if it is spinning: */ if(navigationMode==SPINNING) deactivate(); /* Go to widget interaction mode: */ navigationMode=WIDGETING; } else { /* Try activating this tool: */ if(navigationMode==SPINNING||activate()) startRotating(); } } else { /* Try activating this tool: */ if(navigationMode==SPINNING||activate()) startRotating(); } break; case PANNING: if(dolly) startDollying(); else startScaling(); break; default: /* This shouldn't happen; just ignore the event */ break; } } else // Button has just been released { /* Act depending on this tool's current state: */ switch(navigationMode) { case WIDGETING: { if(GUIInteractor::isActive()) { /* Deliver the event: */ GUIInteractor::buttonUp(); } /* Deactivate this tool: */ navigationMode=IDLE; break; } case ROTATING: { /* Check if the input device is still moving: */ Point currentPos=calcScreenPos(); Vector delta=currentPos-lastRotationPos; if(Geometry::mag(delta)>factory->spinThreshold) { /* Calculate spinning angular velocity: */ Vector offset=(lastRotationPos-screenCenter)+rotateOffset; Vector axis=Geometry::cross(offset,delta); Scalar angularVelocity=Geometry::mag(delta)/(factory->rotateFactor*(getApplicationTime()-lastMoveTime)); spinAngularVelocity=axis*(Scalar(0.5)*angularVelocity/axis.mag()); /* Go to spinning mode: */ navigationMode=SPINNING; } else { /* Deactivate this tool: */ deactivate(); /* Go to idle mode: */ navigationMode=IDLE; } break; } case DOLLYING: case SCALING: startPanning(); break; default: /* This shouldn't happen; just ignore the event */ break; } } break; case 1: if(cbData->newButtonState) // Button has just been pressed { /* Act depending on this tool's current state: */ switch(navigationMode) { case IDLE: case SPINNING: /* Try activating this tool: */ if(navigationMode==SPINNING||activate()) startPanning(); break; case ROTATING: if(dolly) startDollying(); else startScaling(); break; default: /* This shouldn't happen; just ignore the event */ break; } } else // Button has just been released { /* Act depending on this tool's current state: */ switch(navigationMode) { case PANNING: /* Deactivate this tool: */ deactivate(); /* Go to idle mode: */ navigationMode=IDLE; break; case DOLLYING: case SCALING: startRotating(); break; default: /* This shouldn't happen; just ignore the event */ break; } } break; case 2: /* Set the dolly flag: */ dolly=cbData->newButtonState; if(factory->invertDolly) dolly=!dolly; if(dolly) // Dollying has just been enabled { /* Act depending on this tool's current state: */ switch(navigationMode) { case SCALING: startDollying(); break; default: /* Nothing to do */ break; } } else { /* Act depending on this tool's current state: */ switch(navigationMode) { case DOLLYING: startScaling(); break; default: /* Nothing to do */ break; } } break; } }
void ButtonInputDeviceTool::buttonCallback(int,int buttonIndex,InputDevice::ButtonCallbackData* cbData) { if(cbData->newButtonState) // Button has just been pressed { switch(buttonIndex) { case 0: // Device switch button grabNextDevice(); break; case 1: // Transformation mode toggle if(transformationMode==TRANSLATING) transformationMode=ROTATING; else transformationMode=TRANSLATING; break; case 2: // Navigation buttons case 3: case 4: case 5: case 6: case 7: if(!navButtonStates[buttonIndex-2]) { navButtonStates[buttonIndex-2]=true; if(numPressedNavButtons==0) lastFrameTime=getApplicationTime(); ++numPressedNavButtons; } break; default: // Device button buttons if(isActive()&&buttonIndex-8<getGrabbedDevice()->getNumButtons()) getGrabbedDevice()->setButtonState(buttonIndex-8,true); } } else // Button has just been released { switch(buttonIndex) { case 0: // Device switch button case 1: // Transformation mode toggle break; case 2: // Navigation buttons case 3: case 4: case 5: case 6: case 7: if(navButtonStates[buttonIndex-2]) { navButtonStates[buttonIndex-2]=false; --numPressedNavButtons; } break; default: // Device button buttons if(isActive()&&buttonIndex-8<getGrabbedDevice()->getNumButtons()) getGrabbedDevice()->setButtonState(buttonIndex-8,false); } } }
void MouseNavigationTool::frame(void) { /* Update the current mouse position: */ Point newCurrentPos=calcScreenPos(); if(currentPos!=newCurrentPos) { currentPos=calcScreenPos(); lastMoveTime=getApplicationTime(); } if(factory->interactWithWidgets) { /* Update the GUI interactor: */ GUIInteractor::updateRay(); GUIInteractor::move(); } /* Act depending on this tool's current state: */ switch(navigationMode) { case ROTATING: { /* Calculate the rotation position: */ Vector offset=(lastRotationPos-screenCenter)+rotateOffset; /* Calculate mouse displacement vector: */ Point rotationPos=currentPos; Vector delta=rotationPos-lastRotationPos; lastRotationPos=rotationPos; /* Calculate incremental rotation: */ Vector axis=Geometry::cross(offset,delta); Scalar angle=Geometry::mag(delta)/factory->rotateFactor; if(angle!=Scalar(0)) rotation.leftMultiply(NavTrackerState::rotate(NavTrackerState::Rotation::rotateAxis(axis,angle))); NavTrackerState t=preScale; t*=rotation; t*=postScale; setNavigationTransformation(t); break; } case SPINNING: { /* Calculate incremental rotation: */ rotation.leftMultiply(NavTrackerState::rotate(NavTrackerState::Rotation::rotateScaledAxis(spinAngularVelocity*getFrameTime()))); NavTrackerState t=preScale; t*=rotation; t*=postScale; setNavigationTransformation(t); scheduleUpdate(getApplicationTime()+1.0/125.0); break; } case PANNING: { /* Update the navigation transformation: */ NavTrackerState t=NavTrackerState::translate(currentPos-motionStart); t*=preScale; setNavigationTransformation(t); break; } case DOLLYING: { /* Calculate the current dollying direction: */ Scalar viewport[4]; ONTransform screenT=getMouseScreenTransform(mouseAdapter,viewport); Vector dollyingDirection=screenT.transform(factory->screenDollyingDirection); /* Update the navigation transformation: */ Scalar dollyDist=((currentPos-motionStart)*dollyingDirection)/factory->dollyFactor; NavTrackerState t=NavTrackerState::translate(dollyDirection*dollyDist); t*=preScale; setNavigationTransformation(t); break; } case SCALING: { /* Calculate the current scaling direction: */ Scalar viewport[4]; ONTransform screenT=getMouseScreenTransform(mouseAdapter,viewport); Vector scalingDirection=screenT.transform(factory->screenScalingDirection); /* Update the navigation transformation: */ Scalar scale=((currentPos-motionStart)*scalingDirection)/factory->scaleFactor; NavTrackerState t=preScale; t*=NavTrackerState::scale(Math::exp(scale)); t*=postScale; setNavigationTransformation(t); break; } case DOLLYING_WHEEL: { /* Update the navigation transformation: */ Scalar scale=currentValue; currentWheelScale+=factory->wheelDollyFactor*scale; NavTrackerState t=NavTrackerState::translate(dollyDirection*currentWheelScale); t*=preScale; setNavigationTransformation(t); break; } case SCALING_WHEEL: { /* Update the navigation transformation: */ Scalar scale=currentValue; currentWheelScale*=Math::pow(factory->wheelScaleFactor,scale); NavTrackerState t=preScale; t*=NavTrackerState::scale(currentWheelScale); t*=postScale; setNavigationTransformation(t); break; } default: ; } }