![]() |
TAPs 0.7.7.3
|
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