mouse.cpp

00001 
00002 #include "main.h"
00003 #include "mouse.h"
00004 
00005 
00006 
00007 // constructor
00008 Mouse::Mouse( NxReal size, NxReal mouseOperatingHight, NxReal pickedActorLiftUp )
00009 : mouseActor(NULL), 
00010   joint(NULL), 
00011   mouseOperatingHight(mouseOperatingHight),
00012   pickedActorLiftUp(pickedActorLiftUp)
00013 {
00014         logger->log( "Mouse ctor()" );
00015         this->createMouseActor( size );
00016 }
00017 
00018 
00019 // destructor
00020 Mouse::~Mouse()
00021 {
00022         // todo: Avoid release calls while the scene is simulating (in between simulate() and fetchResults() calls)
00023         if ( NULL != this->joint )
00024         {
00025                 nxScene->releaseJoint( *this->joint );
00026                 this->joint = NULL;
00027         }
00028         if ( NULL != this->mouseActor )
00029         {
00030                 nxScene->releaseActor( *this->mouseActor );
00031                 this->mouseActor = NULL;
00032         }
00033 
00034         logger->log( "Mouse dtor()" );
00035 }
00036 
00037 
00038 // set new position on virtual plane, transformed from screen x/y
00039 ERR_TYPE Mouse::moveTo( NxU32 x, NxU32 y )
00040 {
00041         if ( NULL != this->mouseActor )
00042         {
00043                 // wake up our joint members to ensure movement even mouse stands still
00044                 // is joint active?
00045                 if ( NULL != this->joint )
00046                 {
00047                         NxActor* tempActor;
00048                         NxActor* tempMouse;     // unused
00049                         this->joint->getActors( &tempActor, &tempMouse );
00050                         tempActor->wakeUp();
00051                 }
00052                 // create a line from camera to mouseX, mouseY hitPoint in 3D space
00053                 line3df line = getCameraToTableRay( x, y );
00054                 // get intersection between line and table
00055                 NxVec3 intersection = getRayIntersectionWithTable( line );
00056                 // move the virtual mouse pointer on the table
00057                 NxVec3 newPos( intersection.x, this->mouseOperatingHight, intersection.z );
00058                 this->mouseActor->setGlobalPosition( newPos );
00059         }
00060 
00061         return ERR_OK;
00062 }
00063 
00064 
00065 // lift actor and create DistanceJoint with our mouseActor
00066 ERR_TYPE Mouse::pickActorElasticStrap( NxActor* actor )
00067 {
00068         if ( NULL != actor )
00069         {
00070                 // lift picked actor up
00071                 NxVec3 actorPos( actor->getGlobalPosition() );
00072                 actorPos.y += this->pickedActorLiftUp;
00073                 actor->setGlobalPosition( actorPos );
00074                 
00075                 // use our mouse position -SomeHightOffset as new joint position
00076                 NxVec3 jointPos( this->mouseActor->getGlobalPosition() );
00077                 jointPos.y -= 1.0f;
00078         
00079                 // create a joint between our mouse and picked actor
00080                 this->createDistanceJoint( actor, jointPos );
00081         }
00082         
00083         return ERR_OK;
00084 }
00085 
00086 
00087 // lift actor and create SphericalJoint with our mouseActor
00088 ERR_TYPE Mouse::pickActorFixed( NxActor* actor )
00089 {
00090         if ( NULL != actor )
00091         {
00092                 // lift picked actor up and disable dynamic behaviour
00093                 NxVec3 actorPos( actor->getGlobalPosition() );
00094                 actorPos.y += this->pickedActorLiftUp;
00095                 actor->setGlobalPosition( actorPos );
00096                 actor->raiseBodyFlag( NX_BF_FROZEN_ROT );
00097                 
00098                 // use our mouse position -SomeHightOffset as new joint position
00099                 NxVec3 jointPos( this->mouseActor->getGlobalPosition() );
00100                 jointPos.y -= 1.0f;
00101 
00102                 // create a joint between our mouse and picked actor
00103                 this->createSphericalJoint( actor, jointPos );
00104         }
00105         
00106         return ERR_OK;
00107 }
00108 
00109 
00110 // release joint with active actor
00111 ERR_TYPE Mouse::dropActor()
00112 {
00113         // is our joint active?
00114         if ( NULL != this->joint )
00115         {
00116                 // re-enable dynamic bahaviour ( case: fixed type joint )
00117                 NxActor* tempActor;
00118                 NxActor* tempMouse;     // unused
00119                 this->joint->getActors( &tempActor, &tempMouse );
00120                 tempActor->clearBodyFlag( NX_BF_FROZEN_ROT );
00121 
00122                 nxScene->releaseJoint( *this->joint );
00123                 this->joint = NULL;
00124                 //logger->log( "Joint deleted" );
00125         }
00126 
00127         return ERR_OK;
00128 }
00129 
00130 
00131 // returns valid NxActor if mouse raycast hits an actor in the scene,
00132 // transformed from screen x/y
00133 // NULL otherwise 
00134 NxActor* Mouse::actorHit( NxU32 inX, NxU32 inY )
00135 {
00136         // create a line from camera to mouseX, mouseY hitPoint in 3D space
00137         line3df line = this->getCameraToTableRay( inX, inY );
00138 
00139         // create a NxRay from that line
00140         NxVec3 rayStart( line.start.X, line.start.Y, line.start.Z );
00141         NxVec3 rayEnd( line.end.X, line.end.Y, line.end.Z );
00142         NxVec3 rayDir = rayEnd - rayStart;
00143         rayDir.normalize();
00144 
00145         NxRay theRay( rayStart, rayDir );
00146 
00147         // feed physx with that ray and look if it hits something
00148         NxRaycastHit hit;
00149         NxShape* thePickedPhotoShape = NULL;
00150         thePickedPhotoShape = nxScene->raycastClosestShape( theRay, NX_ALL_SHAPES, hit );
00151 
00152         if ( NULL != thePickedPhotoShape )
00153         {
00154                 return &thePickedPhotoShape->getActor();
00155         }
00156 
00157         return NULL;
00158 }
00159 
00160 
00161 
00162 
00163 // *** private: ***
00164 
00165 
00166 // creates our virtual NxActor used to create a joint on any photo
00167 // this actor is used as a mouse pointer
00168 ERR_TYPE Mouse::createMouseActor( NxReal size )
00169 {
00170         // box dimension in [m] on a side
00171         NxVec3 boxDim( size, size, size );
00172 
00173     // Add a single-shape actor to the scene
00174     NxActorDesc actorDesc;
00175     NxBodyDesc bodyDesc;
00176 
00177     // The actor has one shape, a box
00178     NxBoxShapeDesc boxDesc;
00179         boxDesc.dimensions.set( boxDim );
00180 
00181         // this virtual mouse pointer box should not respond to raycasts
00182         // because it would block our "photo hit test" as it is always between the camera and table
00183         boxDesc.shapeFlags |= NX_SF_DISABLE_RAYCASTING;
00184 
00185         // we put the box shape at a local "bootom" position within the actor.
00186         boxDesc.localPose.t = NxVec3( 0.0f, boxDim.y, 0.0f );
00187 
00188         actorDesc.shapes.pushBack( &boxDesc );
00189 
00190     actorDesc.body = &bodyDesc;
00191     actorDesc.density = 10000.0f;
00192 
00193     this->mouseActor = nxScene->createActor( actorDesc );
00194         if ( NULL == this->mouseActor )
00195         {
00196                 logger->log( "createMouseActor() cannot create NxActor" );
00197                 return ERR_MOUSE_CREATE_MOUSE_FAILED;
00198         }
00199 
00200         this->mouseActor->setName( "MousePointer" );
00201         // set kind of static behavior. no forces, no gravity...
00202         this->mouseActor->raiseBodyFlag( NX_BF_KINEMATIC );
00203         // be invisible for other objects
00204         this->mouseActor->raiseActorFlag( NX_AF_DISABLE_COLLISION );
00205 
00206         return ERR_OK;
00207 }
00208 
00209 
00210 // setup our joint with type "DistanceJoint with Spring"
00211 ERR_TYPE Mouse::createDistanceJoint( NxActor* actor, NxVec3 position )
00212 {
00213         NxDistanceJointDesc jointDesc;
00214         jointDesc.name = "MousePick";
00215         jointDesc.actor[0] = actor;
00216         jointDesc.actor[1] = this->mouseActor;
00217         // maximum rest length of the rope or rod between the two anchor points
00218         jointDesc.maxDistance = 2.0f;
00219         // minimum rest length of the rope or rod between the two anchor points
00220         jointDesc.minDistance = 1.0f;
00221         // combination of the bits defined by ::NxDistanceJointFlag
00222         jointDesc.flags = ( NX_DJF_MIN_DISTANCE_ENABLED | NX_DJF_MAX_DISTANCE_ENABLED );
00223         
00224         // compute "pick global pos" to "photo local pos"
00225         NxMat34 photoInverse;
00226         actor->getGlobalPose().getInverse( photoInverse );
00227         NxVec3 photoLocalPos;
00228         photoInverse.multiply( this->mouseActor->getGlobalPosition(), photoLocalPos );
00229         photoLocalPos.y = 0.0f; // y: center of photo boundingbox
00230 
00231         // set both anchor points of joint
00232         jointDesc.localAnchor[0] = photoLocalPos;       // where screen mouse hits photo
00233         jointDesc.localAnchor[1] = NxVec3(0.0f, 0.0f, 0.0f);    // center of mouse' virtual bounding box
00234 
00235         // makes the joint springy. The spring.targetValue field is not used.
00236         NxSpringDesc spring;
00237         spring.spring = 90000.0;
00238         spring.damper = 80000.0f;
00239         jointDesc.spring = spring; 
00240         jointDesc.flags |= NX_DJF_SPRING_ENABLED;
00241         
00242         jointDesc.jointFlags |= NX_JF_VISUALIZATION;
00243 
00244         // check if we have done things right
00245         if ( jointDesc.isValid() )
00246         {
00247                 this->joint = nxScene->createJoint( jointDesc );
00248                 if ( NULL != joint )
00249                 {
00250                         //logger->log( "Joint created" );
00251                 }
00252                 else
00253                 {
00254                         logger->log( "Cannot create joint to pick photo" );
00255                         return ERR_MOUSE_CREATE_JOINT_FAILED;
00256                 }
00257         }
00258         else
00259         {
00260                 logger->log( "Cannot create joint to pick photo" );
00261                 return ERR_MOUSE_CREATE_JOINT_FAILED;
00262         }
00263 
00264         return ERR_OK;
00265 }
00266 
00267 
00268 // setup our joint with type "SphericalJoint"
00269 ERR_TYPE Mouse::createSphericalJoint( NxActor* actor, NxVec3 position )
00270 {
00271         NxSphericalJointDesc jointDesc;
00272         jointDesc.name = "MousePick";
00273         jointDesc.actor[0] = actor;             // set picked photo as joint memeber 1
00274         jointDesc.actor[1] = this->mouseActor;  // set virtual mouse actor as joint memeber 2
00275         jointDesc.jointFlags |= NX_JF_VISUALIZATION;            // enable debug visuals
00276         jointDesc.setGlobalAnchor( position );
00277         jointDesc.setGlobalAxis( NxVec3(0.0f, 1.0f, 0.0f) );    // +Y is your up-axis
00278         
00279         // check if we have done things right
00280         if ( jointDesc.isValid() )
00281         {
00282                 this->joint = nxScene->createJoint( jointDesc );
00283                 if ( NULL != joint )
00284                 {
00285                         //logger->log( "Joint created" );
00286                 }
00287                 else
00288                 {
00289                         logger->log( "Cannot create joint to pick photo" );
00290                         return ERR_MOUSE_CREATE_JOINT_FAILED;
00291                 }
00292         }
00293         else
00294         {
00295                 logger->log( "Cannot create joint to pick photo" );
00296                 return ERR_MOUSE_CREATE_JOINT_FAILED;
00297         }
00298 
00299         return ERR_OK;
00300 }
00301 
00302 
00303 // return 3D point, where ray hits table
00304 NxVec3 Mouse::getRayIntersectionWithTable( line3df line )
00305 {
00306         f32 tableSurfaceYPos = 10.0f;
00307 
00308         //create a plane, representing the table
00309         plane3df tempTable = plane3df( vector3df( -100.0f,  tableSurfaceYPos,  100.0f ),
00310                                                                    vector3df(  100.0f,  tableSurfaceYPos,  100.0f ),
00311                                                                    vector3df(    0.0f,  tableSurfaceYPos, -100.0f ) );
00312 
00313         // use irrlicht to get intersection between line and table
00314         vector3df theIntersection;
00315         tempTable.getIntersectionWithLimitedLine( line.start, line.end, theIntersection );
00316         
00317         // todo: use physx
00318         NxVec3 result( theIntersection.X, theIntersection.Y, theIntersection.Z );
00319 
00320         return result;
00321 }
00322 
00323 
00324 // returns a ray from camera to table at mouse position x/y
00325 line3df Mouse::getCameraToTableRay( s32 mouseX, s32 mouseY )
00326 {
00327         line3df line( 0, 0, 0, 0, 0, 0 );
00328 
00329         ICameraSceneNode* aCam = smgr->getActiveCamera();
00330 
00331         const SViewFrustum* f = aCam->getViewFrustum();
00332 
00333         vector3df farLeftUp = f->getFarLeftUp();
00334         vector3df lefttoright = f->getFarRightUp() - farLeftUp;
00335         vector3df uptodown = f->getFarLeftDown() - farLeftUp;
00336 
00337         rect<s32> viewPort = driver->getViewPort();
00338         dimension2d<s32> screenSize(viewPort.getWidth(), viewPort.getHeight());
00339 
00340         f32 dx = mouseX / (f32)screenSize.Width;
00341         f32 dy = mouseY / (f32)screenSize.Height;
00342 
00343         line.start = f->cameraPosition;
00344         line.end = farLeftUp + (lefttoright * dx) + (uptodown * dy);
00345 
00346         return line;
00347 }

Generated on Sun Dec 2 03:10:23 2007 for TableTop by  doxygen 1.5.4