TAPs 0.7.7.3
TAPsHapticManager.cpp
Go to the documentation of this file.
00001 /******************************************************************************
00002 TAPsHapticManager.cpp
00003 
00004 Inherited from class BaseHapticManager
00005 
00006 SUKITTI PUNAK   (07/21/2005)
00007 UPDATE          (07/30/2005)
00008 ******************************************************************************/
00009 #include "TAPsHapticManager.hpp"
00010 // Using Inclusion Model (i.e. definitions are included in declarations)
00011 //                       (this name.cpp is included in name.hpp)
00012 // Each friend is defined directly inside its declaration.
00013 
00014 //-----------------------------------------------------------------------------
00015 // DEBUG ENABLE
00016 #ifdef TAPs_ENABLE_DEBUG
00017     #define DEBUG_MESSAGE_TAPs_HAPTIC_MANAGER_HPP
00018 #endif
00019 //-----------------------------------------------------------------------------
00020 
00021 BEGIN_NAMESPACE_TAPs__Haptic
00022 //=============================================================================
00023 //-----------------------------------------------------------------------------
00024 // Default Constructor
00025 template <typename T>
00026 HapticManager<T>::HapticManager ()
00027     : BaseHapticManager<T>(),
00028       m_pPointManager( NULL ),
00029       m_pViewManager( NULL ),
00030       m_iManipPoint( -1 ),
00031       m_uiPointNameBase( 0 ),
00032       m_uiEffectName( 0 ),
00033       m_tCursorScale( 1.0 ),
00034       m_uiCursorDisplayList( 0 ),
00035       m_hHD( HD_INVALID_HANDLE ),
00036       m_hHLRC( NULL )
00037 {}
00038 //-----------------------------------------------------------------------------
00039 // Destructor
00040 template <typename T>
00041 HapticManager<T>::~HapticManager ()
00042 {}
00043 //-----------------------------------------------------------------------------
00044 // Setup
00045 // creates a random cloud of points with random colors within a canonical view.
00046 template <typename T>
00047 void HapticManager<T>::Setup (  
00048         TAPs::OpenGL::BasePointManager<T> * pPointManager,
00049         TAPs::OpenGL::OpenGLBaseViewManager<T>  * pViewManager )
00050 {
00051     m_pPointManager = pPointManager;
00052     assert( m_pPointManager );
00053     m_pViewManager = pViewManager;
00054     assert( m_pViewManager );
00055     //----------------------------------------------------------------
00056     // Check Haptic Device
00057     HDErrorInfo error;
00058     m_hHD = hdInitDevice( HD_DEFAULT_DEVICE );
00059     if ( HD_DEVICE_ERROR( error = hdGetError() ) ) {
00060         hduPrintError( stderr, &error, 
00061             "Failed to initialize haptic device!" );
00062         fprintf( stderr, "Press any key to exit" );
00063         getchar();
00064         exit(1);
00065     }
00066     //----------------------------------------------------------------
00067     // Create a haptic context for the device.
00068     // The haptic context maintains the state that persists between 
00069     // frame intervals and is used for haptic rendering.
00070     m_hHLRC = hlCreateContext( m_hHD );
00071     hlMakeCurrent( m_hHLRC );
00072     int iNumPoints = pPointManager->GetNumPoints();
00073     m_uiPointNameBase = hlGenShapes( iNumPoints );
00074     for ( int i = 0; i < iNumPoints; ++i ) {
00075         // Register event callbacks for all of the points, so we can 
00076         // be notified when the points are touched and untouched.
00077         HLuint uiPointName = m_uiPointNameBase + i;
00078         hlAddEventCallback( HL_EVENT_TOUCH, uiPointName, 
00079                             HL_CLIENT_THREAD, hlTouchCB, this );
00080         hlAddEventCallback( HL_EVENT_UNTOUCH, uiPointName, 
00081                             HL_CLIENT_THREAD, hlTouchCB, this );
00082         hlAddEventCallback( HL_EVENT_1BUTTONDOWN, uiPointName, 
00083                             HL_CLIENT_THREAD, hlButtonDownCB, this );
00084     }
00085     //----------------------------------------------------------------
00086     hlAddEventCallback( HL_EVENT_1BUTTONUP, HL_OBJECT_ANY,
00087                         HL_CLIENT_THREAD, hlButtonUpCB, this );
00088     //----------------------------------------------------------------
00089     // Start an ambient drag friction effect
00090     //m_uiEffectName = hlGenEffects( 1 );
00091     //hlBeginFrame();
00092     //  hlEffectd( HL_EFFECT_PROPERTY_GAIN, 0.4 );
00093     //  hlEffectd( HL_EFFECT_PROPERTY_MAGNITUDE, 0.1 );
00094     //  hlStartEffect( HL_EFFECT_FRICTION, m_uiEffectName );
00095     //hlEndFrame();
00096     //----------------------------------------------------------------
00097 }
00098 //-----------------------------------------------------------------------------
00099 // Cleanup
00100 template <typename T>
00101 void HapticManager<T>::Cleanup ()
00102 {
00103     if ( m_hHLRC != NULL ) {
00104         assert( m_pPointManager );
00105         //hlBeginFrame();
00106         //  hlStopEffect( m_uiEffectName );
00107         //hlEndFrame();
00108         //------------------------------------------------------
00109         //hlDeleteEffects( m_uiEffectName, 1 );
00110         int iNumPoints = m_pPointManager->GetNumPoints();
00111         for ( int i = 0; i < iNumPoints; ++i ) {
00112             // Unregister event callbacks for all of the points
00113             HLuint uiPointName = m_uiPointNameBase + i;
00114             hlRemoveEventCallback(  HL_EVENT_TOUCH, uiPointName,
00115                                     HL_CLIENT_THREAD, hlTouchCB );
00116             hlRemoveEventCallback(  HL_EVENT_UNTOUCH, uiPointName,
00117                                     HL_CLIENT_THREAD, hlTouchCB );
00118             hlRemoveEventCallback(  HL_EVENT_1BUTTONDOWN, uiPointName,
00119                                     HL_CLIENT_THREAD, hlButtonDownCB );
00120         }
00121         //------------------------------------------------------
00122         hlRemoveEventCallback(  HL_EVENT_1BUTTONUP, HL_OBJECT_ANY, 
00123                                 HL_CLIENT_THREAD, hlButtonUpCB );
00124         hlDeleteShapes( m_uiPointNameBase, iNumPoints );
00125         hlMakeCurrent( NULL );
00126         hlDeleteContext( m_hHLRC );
00127     }
00128     //----------------------------------------------------------------
00129     if ( m_hHD != HD_INVALID_HANDLE )   hdDisableDevice( m_hHD );
00130 }
00131 //-----------------------------------------------------------------------------
00132 // UpdateWorkSpace
00133 // uses the current OpenGL viewing transforms to initialize a transform for the 
00134 // haptic device workspace so that it's properly mapped to world coordinates.
00135 template <typename T>
00136 void HapticManager<T>::UpdateWorkSpace ()
00137 {
00138     GLdouble modelview[16];
00139     GLdouble projection[16];
00140     GLint viewport[4];
00141     glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
00142     glGetDoublev( GL_PROJECTION_MATRIX, projection );
00143     glGetIntegerv( GL_VIEWPORT, viewport );
00144     hlMatrixMode( HL_TOUCHWORKSPACE );
00145     hlLoadIdentity();
00146     // Use of a non-uniform workspace fit, which offer a maximal fit to the view 
00147     // frustum but introduces non-uniform scale in the workspace.
00148     // This non-uniform scale is fine for point and line based haptics, like 
00149     // this example, but can introduct distortion when actually feeling surfaces 
00150     // (i.e. a sphere might feel like an ellipsoid)
00151     hluFitWorkspaceNonUniform( projection );
00152 }
00153 //-----------------------------------------------------------------------------
00154 // DrawCursor
00155 // displays a cursor using the current haptic device proxy transform and the 
00156 // mapping between the workspace and the world coordinates
00157 template <typename T>
00158 void HapticManager<T>::DrawCursor ()
00159 {
00160     static const double K_CURSOR_SIZE_PIXELS = 15;
00161     static const double K_CURSOR_RADIUS = 0.5;
00162     static const int K_CURSOR_TESS = 15;
00163     HLdouble transform[16];
00164     GLUquadricObj *qObj = NULL;
00165     //-------------------------------------------------------------------
00166     glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT );
00167     glPushMatrix();
00168     //-------------------------------------------------------------------
00169     if ( !m_uiCursorDisplayList ) {
00170         m_uiCursorDisplayList = glGenLists( 1 );
00171         glNewList( m_uiCursorDisplayList, GL_COMPILE );
00172         qObj = gluNewQuadric();
00173         gluSphere( qObj, K_CURSOR_RADIUS, K_CURSOR_TESS, K_CURSOR_TESS );
00174         gluDeleteQuadric( qObj );
00175         glEndList();
00176     }
00177     //-------------------------------------------------------------------
00178     // Apply the local position/rotation transform of the haptic device 
00179     // proxy
00180     hlGetDoublev( HL_PROXY_TRANSFORM, transform );
00181     glMultMatrixd( transform );
00182     //-------------------------------------------------------------------
00183     // Apply the local cursor scale factor
00184     double scale = m_pViewManager->GetWindowToWorldScale() * K_CURSOR_SIZE_PIXELS;
00185     glScaled( scale, scale, scale );
00186     glEnable( GL_NORMALIZE );
00187     glEnable( GL_COLOR_MATERIAL );
00188     glColor3f( 1.0, 1.0, 1.0 );
00189     glCallList( m_uiCursorDisplayList );
00190     //-------------------------------------------------------------------
00191     glPopMatrix();
00192     glPopAttrib();
00193 }
00194 //-----------------------------------------------------------------------------
00195 // FeelPoints
00196 // draw points and lines for haptic device
00197 template <typename T>
00198 void HapticManager<T>::FeelPoints ()
00199 {
00200     hlBeginFrame();
00201     //-------------------------------------------------------------------
00202     int iNumPoints = m_pPointManager->GetNumPoints();
00203     for ( int i = 0; i < iNumPoints; ++i ) {
00204         //------------------------------------------------------
00205         // Don't haptically draw a selected point, since it's 
00206         // being manipulated
00207         if ( m_iManipPoint == i )   continue;
00208         //------------------------------------------------------
00209         // Draw a shape that represents the projection of the 
00210         // points to the near and far planes
00211         hlHinti( HL_SHAPE_FEEDBACK_BUFFER_VERTICES, 3 );
00212         hlBeginShape( HL_SHAPE_FEEDBACK_BUFFER, m_uiPointNameBase + i );
00213             hlTouchModel( HL_CONSTRAINT );
00214             hlTouchModelf( HL_SNAP_DISTANCE, 3.5 );
00215             hlMaterialf( HL_FRONT_AND_BACK, HL_STIFFNESS, 0.5 );
00216             hlMaterialf( HL_FRONT_AND_BACK, HL_DAMPING, 0.0 );
00217             hlMaterialf( HL_FRONT_AND_BACK, HL_STATIC_FRICTION, 0.0 );
00218             hlMaterialf( HL_FRONT_AND_BACK, HL_DYNAMIC_FRICTION, 0.0 );
00219             const TAPs::Vector3<T> &pt = m_pPointManager->GetPointPosition(i);
00220             //---------------------------------------------
00221             // Draw a line that represents the projection 
00222             // of the point to the near and far of the view 
00223             // volume
00224             TAPs::Vector3<T> winPt, nearPt, farPt;
00225             m_pViewManager->ToScreen( pt, winPt );
00226             winPt[2] = 0;
00227             m_pViewManager->FromScreen( winPt, nearPt );
00228             winPt[2] = 1;
00229             m_pViewManager->FromScreen( winPt, farPt );
00230             glBegin( GL_LINES );
00231                 glVertex3dv( nearPt );
00232                 glVertex3dv( farPt );
00233             glEnd();
00234             glBegin( GL_POINTS );
00235                 glVertex3dv( pt );
00236             glEnd();
00237         hlEndShape();
00238     }
00239     //-------------------------------------------------------------------
00240     // Call any event callbacks that have been triggered
00241     hlCheckEvents();
00242     //-------------------------------------------------------------------
00243     hlEndFrame();
00244 }
00245 //-----------------------------------------------------------------------------
00246 // IsManipulating
00247 template <typename T>
00248 bool HapticManager<T>::IsManipulating () const
00249 {
00250     return  m_iManipPoint != -1;
00251 }
00252 //-----------------------------------------------------------------------------
00253 //=============================================================================
00254 // Helper Fn(s)
00255 //-----------------------------------------------------------------------------
00256 // StartManipulating
00257 template <typename T>
00258 void HapticManager<T>::StartManipulating ( int i )
00259 {
00260     assert( !IsManipulating() );
00261     assert( 0 <= i && i < m_pPointManager->GetNumPoints() );
00262     m_pPointManager->SetPointSelected( i, true );
00263     hlAddEventCallback( HL_EVENT_MOTION, HL_OBJECT_ANY,
00264                         HL_CLIENT_THREAD, hlMotionCB, this );
00265     m_iManipPoint = i;
00266     TAPs::Vector3<T> proxyPos;
00267     hlGetDoublev( HL_PROXY_POSITION, proxyPos );
00268     TAPs::Vector3<T> offsetWC = m_pPointManager->GetPointPosition(i) - proxyPos;
00269     //----------------------------------------------------------------
00270     // This is a very useful technique for offsetting the user in 
00271     // space so that they begin their manipulation exactly at the 
00272     // location of the selected point.
00273     PushWorkSpaceOffset( offsetWC );
00274 }
00275 //-----------------------------------------------------------------------------
00276 // StopManipulating
00277 template <typename T>
00278 void HapticManager<T>::StopManipulating ()
00279 {
00280     assert( IsManipulating() );
00281     m_pPointManager->SetPointSelected( m_iManipPoint, false );
00282     hlRemoveEventCallback(  HL_EVENT_MOTION, HL_OBJECT_ANY,
00283                             HL_CLIENT_THREAD, hlMotionCB );
00284     m_iManipPoint = -1;
00285     PopWorkSpaceOffset();
00286 }
00287 //-----------------------------------------------------------------------------
00288 // UpdateManipPoint
00289 template <typename T>
00290 void HapticManager<T>::UpdateManipPoint ( const TAPs::Vector3<T> &proxyPos )
00291 {
00292     m_pPointManager->SetPointPosition( m_iManipPoint, proxyPos );
00293 }
00294 //-----------------------------------------------------------------------------
00295 // PushWorkSpaceOffset
00296 template <typename T>
00297 void HapticManager<T>::PushWorkSpaceOffset ( const TAPs::Vector3<T> &offsetWC )
00298 {
00299     const TAPs::Matrix4x4<T> &mWorldToView = m_pViewManager->GetViewTransform();
00300     TAPs::Matrix4x4<T> mViewToTouch;
00301     TAPs::Matrix4x4<T> mTouchToWorkSpace;
00302     hlGetDoublev( HL_VIEWTOUCH_MATRIX, mViewToTouch );
00303     hlGetDoublev( HL_TOUCHWORKSPACE_MATRIX, mTouchToWorkSpace );
00304     TAPs::Matrix4x4<T> mWorldToWorkSpace = mWorldToView * mViewToTouch * mTouchToWorkSpace;
00305     TAPs::Vector3<T> offsetWS;
00306     //mWorldToWorkSpace.multDirMatrix( offsetWC, offsetWS );
00307     offsetWS[0] =   mWorldToWorkSpace[ 0]*offsetWC[0] + 
00308                     mWorldToWorkSpace[ 4]*offsetWC[1] + 
00309                     mWorldToWorkSpace[ 8]*offsetWC[2];
00310     offsetWS[1] =   mWorldToWorkSpace[ 1]*offsetWC[0] + 
00311                     mWorldToWorkSpace[ 5]*offsetWC[1] + 
00312                     mWorldToWorkSpace[ 9]*offsetWC[2];
00313     offsetWS[2] =   mWorldToWorkSpace[ 2]*offsetWC[0] + 
00314                     mWorldToWorkSpace[ 6]*offsetWC[1] + 
00315                     mWorldToWorkSpace[10]*offsetWC[2];
00316     //----------------------------------------------------------------
00317     // Apply the translation in the local coordinates of the workspace
00318     //TAPs::Matrix4x4<T> mTranslateWS = hduMatrix::createTranslation( -offsetWS );
00319     TAPs::Matrix4x4<T> mTranslateWS( 1, 0, 0, 0, 
00320                                      0, 1, 0, 0,
00321                                      0, 0, 1, 0,
00322                                      -offsetWS[0], -offsetWS[1], -offsetWS[2], 1 );
00323     mTouchToWorkSpace.MultRight( mTranslateWS );
00324     hlMatrixMode( HL_TOUCHWORKSPACE );
00325     hlPushMatrix();
00326     hlLoadMatrixd( mTouchToWorkSpace );
00327 }
00328 //-----------------------------------------------------------------------------
00329 // PopWorkSpaceOffset
00330 template <typename T>
00331 void HapticManager<T>::PopWorkSpaceOffset ()
00332 {
00333     hlMatrixMode( HL_TOUCHWORKSPACE );
00334     hlPopMatrix();
00335 }
00336 //-----------------------------------------------------------------------------
00337 // GetPointIndexFromTouchID
00338 template <typename T>
00339 int HapticManager<T>::GetPointIndexFromTouchID ( HLuint id ) const
00340 {
00341     int i = id - m_uiPointNameBase;
00342     assert( 0 <= i && i < m_pPointManager->GetNumPoints() );
00343     return i;
00344 }
00345 //-----------------------------------------------------------------------------
00346 // 
00347 template <typename T>
00348 void HLCALLBACK HapticManager<T>::hlTouchCB ( 
00349         HLenum event, HLuint object, HLenum thread,
00350         HLcache *cache, void *userData )
00351 {
00352     HapticManager *pThis = static_cast<HapticManager *>(userData);
00353     int i = pThis->GetPointIndexFromTouchID( object );
00354     if ( event == HL_EVENT_TOUCH ) {
00355         pThis->m_pPointManager->SetPointHighlighted( i, true );
00356     }
00357     else if ( event == HL_EVENT_UNTOUCH ) {
00358         pThis->m_pPointManager->SetPointHighlighted( i, false );
00359     }
00360 }
00361 //-----------------------------------------------------------------------------
00362 // 
00363 template <typename T>
00364 void HLCALLBACK HapticManager<T>::hlButtonDownCB ( 
00365         HLenum event, HLuint object, HLenum thread,
00366         HLcache *cache, void *userData )
00367 {
00368     HapticManager *pThis = static_cast<HapticManager *>(userData);
00369     int i = pThis->GetPointIndexFromTouchID( object );
00370     if ( !pThis->IsManipulating() ) {
00371         pThis->StartManipulating( i );
00372     }
00373 }
00374 //-----------------------------------------------------------------------------
00375 // 
00376 template <typename T>
00377 void HLCALLBACK HapticManager<T>::hlButtonUpCB ( 
00378         HLenum event, HLuint object, HLenum thread,
00379         HLcache *cache, void *userData )
00380 {
00381     HapticManager *pThis = static_cast<HapticManager *>(userData);
00382     if ( pThis->IsManipulating() ) {
00383         pThis->StopManipulating();
00384     }
00385 }
00386 //-----------------------------------------------------------------------------
00387 // 
00388 template <typename T>
00389 void HLCALLBACK HapticManager<T>::hlMotionCB ( 
00390         HLenum event, HLuint object, HLenum thread,
00391         HLcache *cache, void *userData )
00392 {
00393     HapticManager *pThis = static_cast<HapticManager *>(userData);
00394 
00395     if ( pThis->IsManipulating() ) {
00396         // Get the position of the proxy when the motion was detected
00397         TAPs::Vector3<T> proxyPos;
00398         hlCacheGetDoublev( cache, HL_PROXY_POSITION, proxyPos );
00399         pThis->UpdateManipPoint( proxyPos );
00400     }
00401 }
00402 //-----------------------------------------------------------------------------
00403 //=============================================================================
00404 END_NAMESPACE_TAPs__Haptic
00405 //-----------------------------------------------------------------------------
00406 //345678901234567890123456789012345678901234567890123456789012345678901234567890
00407 //--+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines