Created
January 4, 2011 16:24
-
-
Save martintamare/764989 to your computer and use it in GitHub Desktop.
Ogre 3D Listener that I used to program multi-touch interactions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "listener.h" | |
//-------------------------------- | |
// GLOBAL FOR LEVMAR | |
//-------------------------------- | |
std::map<int,Vector3> mapPoint3DToMatch; | |
std::map<int,Vector2> mapPoint2D; | |
Vector3 vCentreObject = Vector3::ZERO; // Center of rotation ? | |
Vector3 vCentreRotation = Vector3::ZERO; | |
Camera * gmCamera; // Camera use to project | |
OgreListener::OgreListener(OIS::Keyboard *keyboard, Camera* cam, SceneManager *sceneMgr, RenderWindow* Window){ | |
mContinue = true; | |
//-------------------------- | |
// INIT MOUSE KEYBOARD & STUFF | |
//-------------------------- | |
keyboard->setEventCallback(this); | |
mKeyboard = keyboard; | |
mSceneMgr = sceneMgr; | |
mCamNode = cam->getParentSceneNode(); | |
mCamera = cam; | |
gmCamera = cam; | |
mWindow = Window; | |
//----------------------------------- | |
// INIT INTERACTION | |
//----------------------------------- | |
iNbFinger = 0; | |
iCurrentMode = INIT_STATE; | |
iCurrentTechnique = INTERACTION_DS3; | |
selectedNode = NULL; | |
lastSelectedNode = NULL; | |
//------------------------------ | |
// FINGERPRINT | |
//------------------------------ | |
/* | |
fingerprint=new Ogre2dManager; | |
fingerprint->init(mSceneMgr, Ogre::RENDER_QUEUE_OVERLAY, true); | |
Ogre::TextureManager::getSingleton().load("doigt.png",ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); | |
*/ | |
printFinger = false; | |
//----------------------------- | |
// TOUCH STUFF | |
//----------------------------- | |
mtlib_register_listener(this); | |
mtlib_activate_provider(MTLIB_TOUCHPROVIDER_TUIO); | |
//---------------------------- | |
// INIT PICKING | |
//---------------------------- | |
mRaySceneQuery = mSceneMgr->createRayQuery(Ray(),OK_MASK); | |
//------------------------------ | |
// INTERACTION POINTER & VARIABLE | |
//------------------------------ | |
fZ = NULL; | |
fRoll = NULL; | |
vMovePrev = Vector2::ZERO; | |
vYawPrev = Vector2::ZERO; | |
vRollPrev = Vector2::ZERO; | |
vZPrev = Vector2::ZERO; | |
vectorTranslation = Vector3::ZERO; | |
quatRotation = Quaternion::IDENTITY; | |
//----------------------------- | |
// INTERACTION CONSTANT | |
//----------------------------- | |
v3K1 = 10; | |
v3K2 = 10; | |
factorZ = 10; | |
//----------------------------- | |
// CEGUI CONSTANT | |
//----------------------------- | |
createCEGUIevent(); | |
} | |
OgreListener::~OgreListener(){ | |
} | |
//--------------------------------- | |
// CEGUI EVENT | |
//--------------------------------- | |
void OgreListener::createCEGUIevent(){ | |
CEGUI::WindowManager &wmgr = CEGUI::WindowManager::getSingleton(); | |
CEGUI::Window *button = wmgr.getWindow("mainMenu/bQuit"); | |
button->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&OgreListener::quit, this)); | |
} | |
bool OgreListener::quit(const CEGUI::EventArgs &e){ | |
mContinue = false; | |
return true; | |
} | |
//--------------------------------- | |
// KEYBOARD | |
//--------------------------------- | |
bool OgreListener::keyPressed(const OIS::KeyEvent &e){ | |
CEGUI::System &sys = CEGUI::System::getSingleton(); | |
sys.injectKeyDown(e.key); | |
sys.injectChar(e.text); | |
switch (e.key) | |
{ | |
case OIS::KC_ESCAPE: | |
mContinue = false; | |
break; | |
default: | |
break; | |
} | |
return mContinue; | |
} | |
bool OgreListener::keyReleased(const OIS::KeyEvent &e){ | |
CEGUI::System::getSingleton().injectKeyUp(e.key); | |
return true; | |
} | |
//--------------------------------- | |
// RENDER LOOP | |
//--------------------------------- | |
bool OgreListener::frameStarted(const FrameEvent& evt){ | |
// Inputs | |
mtlib_process_message_queue(); | |
mKeyboard->capture(); | |
// We are using information which is share with TouchListener (tuio ...) so we need a mutex ! | |
multiTouchLock.LockWriter(); | |
do_debuginfo(); | |
if(iCurrentTechnique==INTERACTION_DS3){ | |
ds3_interaction(); | |
}else if(iCurrentTechnique==INTERACTION_STICKY){ | |
sticky_interaction(); | |
}else if(iCurrentTechnique==INTERACTION_SCREENSPACE){ | |
nx_interaction(); | |
} | |
multiTouchLock.UnlockWriter(); | |
if(!mWindow->isActive()) mWindow->setActive(true); // Force ogre to refresh when not in focus (tuio simulator ...) | |
return mContinue; | |
} | |
void OgreListener::do_debuginfo(){ | |
/* | |
if(printFinger) | |
{ | |
// print finger | |
std::map<int,Finger*>::iterator it; | |
real x1,y1,x2,y2; | |
for( it = fingerMap.begin(); it != fingerMap.end(); ++it ) | |
{ | |
Vector2 current(it->second->cvec.x,it->second->cvec.y); | |
x1 = ((current.x*2)-1) - 0.05; | |
x2 = ((current.x*2)-1) + 0.05; | |
y1 = -((current.y*2)-1) - 0.05; | |
y2 = -((current.y*2)-1) + 0.05; | |
fingerprint->spriteBltFull("doigt.png", x1, y1, x2, y2); | |
} | |
} | |
*/ | |
} | |
//--------------------------------- | |
// TOUCH EVENT | |
//--------------------------------- | |
void OgreListener::on_touch_detect(TOUCH& args){ | |
int id = args.rid; // id of the finger | |
// test if CEGUI overlay and button to process | |
CEGUI::WindowManager &wmgr = CEGUI::WindowManager::getSingleton(); | |
CEGUI::Window *current = CEGUI::System::getSingleton().getGUISheet(); | |
CEGUI::Vector2 touchpos(args.x*mWindow->getWidth(),args.y*mWindow->getHeight()); | |
CEGUI::EventArgs e; | |
bool handle = false; | |
if(current != NULL){ | |
CEGUI::Window *button = current->getChildAtPosition(touchpos); | |
(button!=NULL) ? button->fireEvent(CEGUI::PushButton::EventClicked, e) : handle = true; | |
} | |
if(handle){ | |
multiTouchLock.LockWriter(); | |
Finger *temp = new Finger(id,args.x,args.y,0,0); | |
updateInteraction(PRESS,id,temp); // We call this function every time, it will take care of everything ! | |
delete temp; | |
multiTouchLock.UnlockWriter(); | |
} | |
} | |
void OgreListener::on_touch_update(TOUCH& args){ | |
//printf("ON TOUCH UPDATe [%d, %f, %f]\n", args.rid, args.x, args.y); | |
int id = args.rid; | |
multiTouchLock.LockWriter(); | |
Finger *temp = new Finger(id,args.x,args.y,0,0); | |
updateInteraction(MOVE,id,temp); // We call this function every time, it will take care of everything ! | |
delete temp; | |
multiTouchLock.UnlockWriter(); | |
} | |
void OgreListener::on_touch_release(TOUCH& args){ | |
int id = args.rid; | |
multiTouchLock.LockWriter(); | |
Finger *temp = new Finger(id,args.x,args.y,0,0); | |
updateInteraction(RELEASE,id,temp); // We call this function every time, it will take care of everything ! | |
delete temp; | |
multiTouchLock.UnlockWriter(); | |
} | |
//------------------------------- | |
// PICKING FUNCTION | |
//------------------------------- | |
bool OgreListener::IsNamePickedOK(String name){ | |
return name.substr(0,5)=="ObjOK"; | |
} | |
int OgreListener::basic_picking(Finger *fPick, Vector3 &Result){ | |
Entity *ent=NULL; | |
MovableObject * mo; | |
Vector3 hitposition; | |
Ray mouseRay = mCamera->getCameraToViewportRay(fPick->cvec.x,fPick->cvec.y); | |
Plane test; | |
PickEntity(mouseRay,&ent,hitposition,test); | |
Result = NULL; | |
mo=ent; | |
if (mo!= NULL) // On a pické un truc | |
{ | |
if(IsNamePickedOK(mo->getName())) | |
{ | |
if(fPick!=NULL){ | |
fPick->picked = true; | |
fPick->picking = mo->getName(); | |
} | |
if(iCurrentScene==SCENE_PEG) | |
{ | |
// Si aucune sélection | |
if(selectedNode==NULL){ | |
selectedNode = mo->getParentSceneNode(); | |
//selectedNode->showBoundingBox(true); | |
Result = hitposition; | |
return PICKING_OK; | |
// Sinon on vérifie qu'on est sur le même objet | |
}else if(selectedNode==mo->getParentSceneNode()){ | |
Result = hitposition; | |
return PICKING_OK; | |
} | |
}else{ | |
selectedNode = mSceneMgr->getSceneNode("Source"); | |
Result = hitposition; | |
return PICKING_OK; | |
} | |
} | |
} | |
return NO_PICK; | |
} | |
int OgreListener::mini_picking(Vector2 pos, Vector3 &Result){ | |
Entity *ent=NULL; | |
MovableObject * mo; | |
Vector3 hitposition; | |
Ray mouseRay = mCamera->getCameraToViewportRay(pos.x,pos.y); | |
Plane test; | |
PickEntity(mouseRay,&ent,hitposition,test); | |
Result = NULL; | |
mo=ent; | |
if (mo!= NULL) // On a pické un truc | |
{ | |
if(IsNamePickedOK(mo->getName())) | |
{ | |
Result = hitposition; | |
return PICKING_OK; | |
} | |
} | |
return NO_PICK; | |
} | |
bool OgreListener::plane_picking(Vector2 pos, Plane plan, Vector3 &Result){ | |
Ray mouseRay = mCamera->getCameraToViewportRay(pos.x,pos.y); | |
std::pair<bool, Real> res = mouseRay.intersects(plan); | |
if(res.first) | |
{ | |
Result = mouseRay.getPoint(res.second); | |
return true; | |
} | |
return false; | |
} | |
//------------------------------- | |
// ADVANCE PICKING FUNCTION | |
//------------------------------- | |
bool OgreListener::PickEntity(Ogre::Ray &ray, Ogre::Entity ** result, Ogre::Vector3 &hitpoint, Ogre::Plane &hitplane, Ogre::uint32 masque){ | |
mRaySceneQuery->setQueryMask(masque); | |
mRaySceneQuery->setRay(ray); | |
mRaySceneQuery->setSortByDistance(true); | |
// Execute query | |
RaySceneQueryResult &query = mRaySceneQuery->execute(); | |
RaySceneQueryResult::iterator itr; | |
if (query.size() <= 0) return (false); | |
// at this point we have raycast to a series of different objects bounding boxes. | |
// we need to test these different objects to see which is the first polygon hit. | |
// there are some minor optimizations (distance based) that mean we wont have to | |
// check all of the objects most of the time, but the worst case scenario is that | |
// we need to test every triangle of every object. | |
Ogre::Real closest_distance = -1.0f; | |
Ogre::Vector3 closest_result; | |
Ogre::RaySceneQueryResult &query_result = mRaySceneQuery->getLastResults(); | |
for (size_t qr_idx = 0; qr_idx < query_result.size(); qr_idx++) | |
{ | |
// stop checking if we have found a raycast hit that is closer | |
// than all remaining entities | |
if ((closest_distance >= 0.0f) && (closest_distance < query_result[qr_idx].distance)) | |
{ | |
break; | |
} | |
// only check this result if its a hit against an entity | |
if ((query_result[qr_idx].movable != NULL) && (query_result[qr_idx].movable->getMovableType().compare("Entity") == 0)) | |
{ | |
// get the entity to check | |
Ogre::Entity *pentity = static_cast<Ogre::Entity*>(query_result[qr_idx].movable); | |
if(!pentity->getVisible()) continue; | |
// mesh data to retrieve | |
size_t vertex_count; | |
size_t index_count; | |
Ogre::Vector3 *vertices; | |
unsigned long *indices; | |
// get the mesh information | |
GetMeshInformationEx(pentity->getMesh(), vertex_count, vertices, index_count, indices, | |
pentity->getParentNode()->_getDerivedPosition(), | |
pentity->getParentNode()->_getDerivedOrientation(), | |
pentity->getParentNode()->_getDerivedScale()); | |
// test for hitting individual triangles on the mesh | |
bool new_closest_found = false; | |
for (int i = 0; i < static_cast<int>(index_count); i += 3) | |
{ | |
// check for a hit against this triangle | |
std::pair<bool, Ogre::Real> hit = Ogre::Math::intersects(ray, vertices[indices[i]], | |
vertices[indices[i+1]], vertices[indices[i+2]], true, false); | |
// if it was a hit check if its the closest | |
if (hit.first) | |
{ | |
if ((closest_distance < 0.0f) || (hit.second < closest_distance)) | |
{ | |
// this is the closest so far, save it off | |
closest_distance = hit.second; | |
new_closest_found = true; | |
hitplane = Plane(vertices[indices[i]],vertices[indices[i+1]],vertices[indices[i+2]]); | |
} | |
} | |
} | |
// free the verticies and indicies memory | |
delete[] vertices; | |
delete[] indices; | |
// if we found a new closest raycast for this object, update the | |
// closest_result before moving on to the next object. | |
if (new_closest_found) | |
{ | |
closest_result = ray.getPoint(closest_distance); | |
(*result) = pentity; | |
} | |
} | |
} | |
// return the result | |
if (closest_distance >= 0.0f) | |
{ | |
hitpoint = closest_result; | |
return (true); | |
} | |
else | |
{ | |
// raycast failed | |
return (false); | |
} | |
} | |
void OgreListener::GetMeshInformationEx(const Ogre::MeshPtr mesh,size_t &vertex_count,Ogre::Vector3* &vertices,size_t &index_count,unsigned long* &indices,const Ogre::Vector3 &position,const Ogre::Quaternion &orient,const Ogre::Vector3 &scale){ | |
bool added_shared = false; | |
size_t current_offset = 0; | |
size_t shared_offset = 0; | |
size_t next_offset = 0; | |
size_t index_offset = 0; | |
vertex_count = index_count = 0; | |
// Calculate how many vertices and indices we're going to need | |
for (unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i) | |
{ | |
Ogre::SubMesh* submesh = mesh->getSubMesh( i ); | |
// We only need to add the shared vertices once | |
if(submesh->useSharedVertices) | |
{ | |
if( !added_shared ) | |
{ | |
vertex_count += mesh->sharedVertexData->vertexCount; | |
added_shared = true; | |
} | |
} | |
else | |
{ | |
vertex_count += submesh->vertexData->vertexCount; | |
} | |
// Add the indices | |
index_count += submesh->indexData->indexCount; | |
} | |
// Allocate space for the vertices and indices | |
vertices = new Ogre::Vector3[vertex_count]; | |
indices = new unsigned long[index_count]; | |
added_shared = false; | |
// Run through the submeshes again, adding the data into the arrays | |
for ( unsigned short i = 0; i < mesh->getNumSubMeshes(); ++i) | |
{ | |
Ogre::SubMesh* submesh = mesh->getSubMesh(i); | |
Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData; | |
if((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared)) | |
{ | |
if(submesh->useSharedVertices) | |
{ | |
added_shared = true; | |
shared_offset = current_offset; | |
} | |
const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION); | |
Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource()); | |
unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); | |
// There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double | |
// as second argument. So make it float, to avoid trouble when Ogre::Real will | |
// be comiled/typedefed as double: | |
// Ogre::Real* pReal; | |
float* pReal; | |
for( size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize()) | |
{ | |
posElem->baseVertexPointerToElement(vertex, &pReal); | |
Ogre::Vector3 pt(pReal[0], pReal[1], pReal[2]); | |
vertices[current_offset + j] = (orient * (pt * scale)) + position; | |
} | |
vbuf->unlock(); | |
next_offset += vertex_data->vertexCount; | |
} | |
Ogre::IndexData* index_data = submesh->indexData; | |
size_t numTris = index_data->indexCount / 3; | |
Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer; | |
bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT); | |
unsigned long* pLong = static_cast<unsigned long*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY)); | |
unsigned short* pShort = reinterpret_cast<unsigned short*>(pLong); | |
size_t offset = (submesh->useSharedVertices)? shared_offset : current_offset; | |
if ( use32bitindexes ) | |
{ | |
for ( size_t k = 0; k < numTris*3; ++k) | |
{ | |
indices[index_offset++] = pLong[k] + static_cast<unsigned long>(offset); | |
} | |
} | |
else | |
{ | |
for ( size_t k = 0; k < numTris*3; ++k) | |
{ | |
indices[index_offset++] = static_cast<unsigned long>(pShort[k]) + static_cast<unsigned long>(offset); | |
} | |
} | |
ibuf->unlock(); | |
current_offset = next_offset; | |
} | |
} | |
//------------------------------ | |
// INTERACTION FUNCTION | |
//------------------------------ | |
void OgreListener::updateInteraction(int iLastTouch, int iLastFinger, Finger *f){ | |
// According to last touch | |
if(iLastTouch==PRESS) | |
{ | |
// insert in the map | |
Finger *temp = new Finger(f); | |
fingerMap.insert(pair<int,Finger*>(f->id,temp)); | |
}else if(iLastTouch==MOVE){ | |
// Update the map | |
std::map<int,Finger*>::iterator it; | |
it=fingerMap.find(f->id); | |
if(it!=fingerMap.end()) it->second->update(f); | |
}else if(iLastTouch==RELEASE){ | |
// Remove from the map | |
int id = f->id; | |
std::map<int,Finger*>::iterator it; | |
it=fingerMap.find(id); | |
if(it!=fingerMap.end()){ | |
delete fingerMap.find(id)->second; | |
fingerMap.erase(id); | |
} | |
} | |
iNbFinger = fingerMap.size(); | |
// The map is used for general purpose, the interaction technique does not use this. | |
// for every interaction technique, we process first the mode, then we extract the data we need ! | |
if(iCurrentTechnique==INTERACTION_DS3){ | |
ds3_mode(iLastTouch,iLastFinger,f); | |
ds3_gesture(iLastTouch,iLastFinger, f); | |
}else if(iCurrentTechnique==INTERACTION_STICKY){ | |
sticky_mode(iLastTouch,iLastFinger,f); | |
sticky_gesture(iLastTouch,iLastFinger, f); | |
}else if(iCurrentTechnique==INTERACTION_SCREENSPACE){ | |
nx_mode(iLastTouch,iLastFinger,f); | |
nx_gesture(iLastTouch,iLastFinger, f); | |
} | |
} | |
void OgreListener::updateSelected(){ | |
lastSelectedNode = selectedNode; | |
//selectedNode->showBoundingBox(false); | |
selectedNode = NULL; | |
} | |
//------------------------------ | |
// DS3 FUNCTION | |
//------------------------------ | |
void OgreListener::ds3_mode(int iLastTouch, int iLastFinger, Finger *f){ | |
// According to the mode and picking we switch mode, build the objectfingers map ! | |
switch(iLastTouch) | |
{ | |
case PRESS: | |
if (iCurrentMode == INIT_STATE) | |
{ | |
Vector3 vPicking; | |
int picked = basic_picking(f,vPicking); | |
if(picked==PICKING_OK) { | |
ObjectFingers.insert(pair<int,Finger> (f->id,Finger(f))); | |
iCurrentMode = TRANSLATION; | |
break; | |
} | |
break; | |
}else if(iCurrentMode == TRANSLATION){ | |
Vector3 vPicking; | |
int picked = basic_picking(f,vPicking); | |
if(picked==PICKING_OK) { | |
ObjectFingers.insert(pair<int,Finger> (f->id,Finger(f))); | |
iCurrentMode = ROTATION; | |
break; | |
}else{ | |
fZ = new Finger(f); | |
iCurrentMode = Z_TRANSLATION; | |
break; | |
} | |
}else if(iCurrentMode == Z_TRANSLATION){ | |
Vector3 vPicking; | |
int picked = basic_picking(f,vPicking); | |
if(picked==PICKING_OK) { | |
ObjectFingers.insert(pair<int,Finger> (f->id,Finger(f))); | |
iCurrentMode = COMBINED; | |
break; | |
} | |
break; | |
}else if(iCurrentMode == ROTATION){ | |
Vector3 vPicking; | |
int picked = basic_picking(f,vPicking); | |
if(picked==NO_PICK) { | |
fZ = new Finger(f); | |
iCurrentMode = COMBINED; | |
break; | |
}else if(picked==PICKING_OK) { | |
ObjectFingers.insert(pair<int,Finger> (f->id,Finger(f))); | |
break; | |
} | |
} | |
break; | |
case MOVE: // Simple update of the finger | |
if(fZ!=NULL && iLastFinger == fZ->id){ | |
fZ->update(f); | |
break; | |
}else if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.find(f->id)->second.update(f); | |
break; | |
} | |
break; | |
case RELEASE: // A bit more tricky | |
if(iCurrentMode == TRANSLATION){ | |
if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
iCurrentMode = INIT_STATE; | |
updateSelected(); | |
break; | |
} | |
break; | |
}else if(iCurrentMode == ROTATION){ | |
if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
if(ObjectFingers.size()==1) | |
{ | |
Vecteur3D temp = ObjectFingers.begin()->second.cvec; | |
Vector3 temp2; | |
// with two fingers, sometimes, when releasing, we are not on the object anymore ... | |
if(mini_picking(Vector2(temp.x,temp.y),temp2)==PICKING_OK){ | |
iCurrentMode = TRANSLATION; | |
}else{ | |
iCurrentMode = NOTHING; | |
} | |
} | |
break; | |
} | |
break; | |
}else if(iCurrentMode == Z_TRANSLATION){ | |
if(fZ!=NULL && iLastFinger == fZ->id){ | |
delete fZ; | |
fZ = NULL; | |
iCurrentMode = TRANSLATION; | |
break; | |
}else if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
if(ObjectFingers.size()==0) | |
{ | |
iCurrentMode = NOTHING; | |
updateSelected(); | |
} | |
break; | |
} | |
break; | |
}else if(iCurrentMode == COMBINED){ | |
if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
int size = ObjectFingers.size(); | |
if(size==1) | |
{ | |
Vector2 temp = Vector2(ObjectFingers.begin()->second.cvec.x,ObjectFingers.begin()->second.cvec.y); | |
Vector3 temp2; | |
int picking = mini_picking(temp,temp2); | |
if(picking==PICKING_OK) | |
{ | |
iCurrentMode = Z_TRANSLATION; | |
vMovePrev = Vector2::ZERO; | |
}else{ | |
iCurrentMode = NOTHING; | |
updateSelected(); | |
} | |
}else if(size==0) | |
{ | |
iCurrentMode = NOTHING; | |
updateSelected(); | |
} | |
break; | |
}else if(fZ!=NULL && iLastFinger == fZ->id){ | |
delete fZ; | |
fZ = NULL; | |
iCurrentMode = ROTATION; | |
break; | |
} | |
break; | |
}else if(iCurrentMode == NOTHING){ | |
if(fZ!=NULL && iLastFinger == fZ->id){ | |
delete fZ; | |
fZ = NULL; | |
}else if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
} | |
if(ObjectFingers.empty() && fZ==NULL) iCurrentMode = INIT_STATE; | |
break; | |
} | |
} | |
} | |
void OgreListener::ds3_gesture(int iLastTouch, int iLastFinger, Finger *f){ | |
if(iCurrentMode == INIT_STATE){ | |
}else if(iCurrentMode == TRANSLATION){ | |
// Only one finger, we use its position to move the object | |
if(ObjectFingers.begin()!=ObjectFingers.end()) | |
{ | |
vMoveCur = Vector2(ObjectFingers.begin()->second.cvec.x,ObjectFingers.begin()->second.cvec.y); | |
} | |
}else if(iCurrentMode == Z_TRANSLATION){ | |
// two fingers : direct and indirect | |
// tz | |
vZCur = Vector2(fZ->cvec.x,fZ->cvec.y); | |
//tx,ty | |
if(ObjectFingers.begin()!=ObjectFingers.end()) | |
{ | |
vMoveCur = Vector2(ObjectFingers.begin()->second.cvec.x,ObjectFingers.begin()->second.cvec.y); | |
} | |
}else if(iCurrentMode == ROTATION){ | |
// We create a map with vector3 : | |
// .x & .y = position | |
// .z = id | |
std::map<int,Finger>::iterator it = ObjectFingers.begin(); | |
vRotationCur.clear(); | |
for(it; it!=ObjectFingers.end();it++) | |
{ | |
vRotationCur.push_back(Vector3(it->second.cvec.x,it->second.cvec.y,it->second.id)); | |
} | |
}else if(iCurrentMode == COMBINED){ | |
// a mix of above | |
std::map<int,Finger>::iterator it = ObjectFingers.begin(); | |
vRotationCur.clear(); | |
for(it; it!=ObjectFingers.end();it++) | |
{ | |
vRotationCur.push_back(Vector3(it->second.cvec.x,it->second.cvec.y,it->second.id)); | |
} | |
vZCur = Vector2(fZ->cvec.x,fZ->cvec.y); | |
} | |
} | |
void OgreListener::ds3_interaction(){ | |
if(iCurrentMode==INIT_STATE){ | |
// reset everything | |
vRotationCur.clear(); | |
vZCur = Vector2::ZERO; | |
vMoveCur = Vector2::ZERO; | |
vMovePrev = Vector2::ZERO; | |
vZPrev = Vector2::ZERO; | |
vRotationPrev.clear(); | |
}else if(iCurrentMode==TRANSLATION){ | |
// tx, ty avec vMoveCur | |
translate(); | |
//update | |
vMovePrev = vMoveCur; | |
// reset other | |
vZPrev = Vector2::ZERO; | |
vRotationPrev.clear(); | |
}else if(iCurrentMode==Z_TRANSLATION){ | |
// tx, ty avec vMoveCur | |
translate(); | |
// tz avec vZCur | |
z_translate(); | |
// update | |
vMovePrev = vMoveCur; | |
vZPrev = vZCur; | |
// reset other | |
vRotationPrev.clear(); | |
}else if(iCurrentMode==ROTATION){ | |
// Handle rx,ry,rz | |
if(vRotationPrev.size() == vRotationCur.size()) | |
{ | |
direct3D_rotation(); | |
}else{ | |
init_direct3D(); | |
} | |
// update | |
vRotationPrev = vRotationCur; | |
//reset other | |
vZPrev = Vector2::ZERO; | |
vMovePrev = Vector2::ZERO; | |
}else if(iCurrentMode==COMBINED){ | |
// Handle rx,ry,rz | |
if(vRotationPrev.size() == vRotationCur.size()) | |
{ | |
direct3D_rotation(); | |
}else{ | |
init_direct3D(); | |
} | |
// tz | |
z_translate(); | |
// update | |
vZPrev = vZCur; | |
vRotationPrev = vRotationCur; | |
// reset other | |
vMovePrev = Vector2::ZERO; | |
} | |
moveObject(); | |
} | |
//------------------------------ | |
// STICKY TOOLS FUNCTION | |
//------------------------------ | |
void OgreListener::sticky_mode(int iLastTouch, int iLastFinger, Finger *f){ | |
switch(iLastTouch) | |
{ | |
case PRESS: | |
if (iCurrentMode == INIT_STATE) | |
{ | |
Vector3 vPicking; | |
int picked = basic_picking(f,vPicking); | |
if(picked==PICKING_OK) { | |
ObjectFingers.insert(pair<int,Finger> (f->id,Finger(f))); | |
iCurrentMode = TRANSLATION; | |
break; | |
} | |
break; | |
}else if(iCurrentMode == TRANSLATION){ | |
Vector3 vPicking; | |
int picked = basic_picking(f,vPicking); | |
if(picked==PICKING_OK) { | |
ObjectFingers.insert(pair<int,Finger> (f->id,Finger(f))); | |
iCurrentMode = TOUCH_2; | |
break; | |
}else{ | |
fRoll = new Finger(f); | |
iCurrentMode = TOUCH_3; | |
break; | |
} | |
}else if(iCurrentMode == TOUCH_3){ | |
Vector3 vPicking; | |
int picked = basic_picking(f,vPicking); | |
if(picked==PICKING_OK) { | |
ObjectFingers.insert(pair<int,Finger> (f->id,Finger(f))); | |
iCurrentMode = COMBINED; | |
break; | |
} | |
break; | |
}else if(iCurrentMode == TOUCH_2){ | |
Vector3 vPicking; | |
int picked = basic_picking(f,vPicking); | |
if(picked==NO_PICK) { | |
fRoll = new Finger(f); | |
iCurrentMode = COMBINED; | |
break; | |
} | |
} | |
break; | |
case MOVE: | |
if(fRoll!=NULL && iLastFinger == fRoll->id){ | |
fRoll->update(f); | |
break; | |
}else if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.find(f->id)->second.update(f); | |
break; | |
} | |
break; | |
case RELEASE: | |
if(iCurrentMode == TRANSLATION){ | |
if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
iCurrentMode = INIT_STATE; | |
updateSelected(); | |
break; | |
} | |
break; | |
}else if(iCurrentMode == TOUCH_2){ | |
if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
if(ObjectFingers.size()==1) | |
{ | |
Vecteur3D temp = ObjectFingers.begin()->second.cvec; | |
Vector3 temp2; | |
if(mini_picking(Vector2(temp.x,temp.y),temp2)==PICKING_OK){ | |
iCurrentMode = TRANSLATION; | |
}else{ | |
iCurrentMode = NOTHING; | |
} | |
} | |
break; | |
} | |
break; | |
}else if(iCurrentMode == TOUCH_3){ | |
if(fRoll!=NULL && iLastFinger == fRoll->id){ | |
delete fRoll; | |
fRoll = NULL; | |
iCurrentMode = TRANSLATION; | |
break; | |
}else if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
if(ObjectFingers.size()==0) | |
{ | |
iCurrentMode = NOTHING; | |
updateSelected(); | |
} | |
break; | |
} | |
break; | |
}else if(iCurrentMode == COMBINED){ | |
if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
int size = ObjectFingers.size(); | |
if(size==1) | |
{ | |
Vector2 temp = Vector2(ObjectFingers.begin()->second.cvec.x,ObjectFingers.begin()->second.cvec.y); | |
Vector3 temp2; | |
int picking = mini_picking(temp,temp2); | |
if(picking==PICKING_OK) | |
{ | |
iCurrentMode = TOUCH_3; | |
vMovePrev = Vector2::ZERO; | |
}else{ | |
iCurrentMode = NOTHING; | |
updateSelected(); | |
} | |
}else if(size==0) | |
{ | |
iCurrentMode = NOTHING; | |
updateSelected(); | |
} | |
break; | |
}else if(fRoll!=NULL && iLastFinger == fRoll->id){ | |
delete fRoll; | |
fRoll = NULL; | |
iCurrentMode = TOUCH_2; | |
break; | |
} | |
break; | |
}else if(iCurrentMode == NOTHING){ | |
if(fRoll!=NULL && iLastFinger == fRoll->id){ | |
delete fRoll; | |
fRoll = NULL; | |
}else if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
} | |
if(ObjectFingers.empty() && fRoll==NULL) iCurrentMode = INIT_STATE; | |
break; | |
} | |
} | |
} | |
void OgreListener::sticky_gesture(int iLastTouch, int iLastFinger, Finger *f){ | |
if(iCurrentMode == INIT_STATE){ | |
}else if(iCurrentMode == TRANSLATION){ | |
//tx,ty | |
if(ObjectFingers.begin()!=ObjectFingers.end()) | |
{ | |
vMoveCur = Vector2(ObjectFingers.begin()->second.cvec.x,ObjectFingers.begin()->second.cvec.y); | |
} | |
}else if(iCurrentMode == TOUCH_3){ | |
//rx, ry | |
vRollCur = Vector2(fRoll->cvec.x,fRoll->cvec.y); | |
//tx,ty | |
if(ObjectFingers.begin()!=ObjectFingers.end()) | |
{ | |
vMoveCur = Vector2(ObjectFingers.begin()->second.cvec.x,ObjectFingers.begin()->second.cvec.y); | |
} | |
}else if(iCurrentMode == TOUCH_2){ | |
// tx, ty, tz, rz | |
std::map<int,Finger>::iterator it = ObjectFingers.begin(); | |
vRotationCur.clear(); | |
for(it; it!=ObjectFingers.end();it++) | |
{ | |
vRotationCur.push_back(Vector3(it->second.cvec.x,it->second.cvec.y,it->second.id)); | |
} | |
}else if(iCurrentMode == COMBINED){ | |
// tx, ty, tz, rz | |
std::map<int,Finger>::iterator it = ObjectFingers.begin(); | |
vRotationCur.clear(); | |
for(it; it!=ObjectFingers.end();it++) | |
{ | |
vRotationCur.push_back(Vector3(it->second.cvec.x,it->second.cvec.y,it->second.id)); | |
} | |
// rx, ry | |
vRollCur = Vector2(fRoll->cvec.x,fRoll->cvec.y); | |
} | |
} | |
void OgreListener::sticky_interaction(){ | |
if(iCurrentMode==INIT_STATE){ | |
vMovePrev = Vector2::ZERO; | |
vRotationPrev.clear(); | |
vRollPrev = Vector2::ZERO; | |
vMoveCur = Vector2::ZERO; | |
vRotationCur.clear(); | |
vRollCur = Vector2::ZERO; | |
}else if(iCurrentMode==TRANSLATION){ | |
// tx, ty | |
translate(); | |
// update | |
vMovePrev = vMoveCur; | |
// reset other | |
vRotationPrev.clear(); | |
vRollPrev = Vector2::ZERO; | |
}else if(iCurrentMode==TOUCH_2){ | |
// tx, ty, tz, rz | |
if(vRotationPrev.size() == vRotationCur.size()) | |
{ | |
sticky_4dof(); | |
}else{ | |
init_direct3D(); | |
} | |
// update | |
vRotationPrev = vRotationCur; | |
// reset other | |
vRollPrev = Vector2::ZERO; | |
vMovePrev = Vector2::ZERO; | |
}else if(iCurrentMode==TOUCH_3){ | |
// tx, ty | |
translate(); | |
// rx, ry | |
shallow_pitch(); | |
// update | |
vMovePrev = vMoveCur; | |
vRollPrev = vRollCur; | |
// reset other | |
vRotationPrev.clear(); | |
}else if(iCurrentMode==COMBINED){ | |
// tx, ty, tz, rz | |
if(vRotationPrev.size() == vRotationCur.size()) | |
{ | |
sticky_4dof(); | |
}else{ | |
init_direct3D(); | |
} | |
// rx,ry | |
shallow_pitch(); | |
// update | |
vRotationPrev = vRotationCur; | |
vRollPrev = vRollCur; | |
// reset other | |
vMovePrev = Vector2::ZERO; | |
} | |
moveObject(); | |
} | |
//------------------------------ | |
// SCREENSPACE FUNCTION | |
//------------------------------ | |
void OgreListener::nx_mode(int iLastTouch, int iLastFinger, Finger *f){ | |
switch(iLastTouch) | |
{ | |
case PRESS: | |
if (iCurrentMode == INIT_STATE) | |
{ | |
Vector3 vPicking; | |
int picked = basic_picking(f,vPicking); | |
if(picked==PICKING_OK) { | |
ObjectFingers.insert(pair<int,Finger> (f->id,Finger(f))); | |
iCurrentMode = TRANSLATION; | |
break; | |
} | |
break; | |
}else if(iCurrentMode == TRANSLATION){ | |
Vector3 vPicking; | |
int picked = basic_picking(f,vPicking); | |
if(picked==PICKING_OK) { | |
ObjectFingers.insert(pair<int,Finger> (f->id,Finger(f))); | |
iCurrentMode = TOUCH_2; | |
break; | |
} | |
}else if(iCurrentMode == TOUCH_2){ | |
Vector3 vPicking; | |
int picked = basic_picking(f,vPicking); | |
if(picked==PICKING_OK) { | |
ObjectFingers.insert(pair<int,Finger> (f->id,Finger(f))); | |
iCurrentMode = TOUCH_3; | |
break; | |
} | |
}else if(iCurrentMode == TOUCH_3){ | |
Vector3 vPicking; | |
int picked = basic_picking(f,vPicking); | |
if(picked==PICKING_OK) { | |
ObjectFingers.insert(pair<int,Finger> (f->id,Finger(f))); | |
break; | |
} | |
} | |
break; | |
case MOVE: | |
if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.find(f->id)->second.update(f); | |
break; | |
} | |
break; | |
case RELEASE: | |
if(iCurrentMode == TRANSLATION){ | |
if(ObjectFingers.find(f->id)!=ObjectFingers.end()) | |
{ | |
ObjectFingers.erase(f->id); | |
iCurrentMode = INIT_STATE; | |
updateSelected(); | |
break; | |
} | |
break; | |
}else if(iCurrentMode == TOUCH_2){ | |
if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
Vecteur3D temp = ObjectFingers.begin()->second.cvec; | |
Vector3 temp2; | |
if(mini_picking(Vector2(temp.x,temp.y),temp2)==PICKING_OK){ | |
iCurrentMode = TRANSLATION; | |
}else{ | |
iCurrentMode = NOTHING; | |
} | |
break; | |
} | |
break; | |
}else if(iCurrentMode == TOUCH_3){ | |
if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
int size = ObjectFingers.size(); | |
if(size==2) | |
{ | |
iCurrentMode = TOUCH_2; | |
break; | |
} | |
} | |
break; | |
}else if(iCurrentMode == NOTHING){ | |
if(ObjectFingers.find(f->id)!=ObjectFingers.end()){ | |
ObjectFingers.erase(f->id); | |
} | |
if(ObjectFingers.empty()) iCurrentMode = INIT_STATE; | |
break; | |
} | |
} | |
} | |
void OgreListener::nx_gesture(int iLastTouch, int iLastFinger, Finger *f){ | |
if(iCurrentMode == INIT_STATE){ | |
}else if(iCurrentMode == TRANSLATION){ | |
if(ObjectFingers.begin()!=ObjectFingers.end()) | |
{ | |
vMoveCur = Vector2(ObjectFingers.begin()->second.cvec.x,ObjectFingers.begin()->second.cvec.y); | |
} | |
}else if(iCurrentMode == TOUCH_2 || iCurrentMode == TOUCH_3){ | |
std::map<int,Finger>::iterator it = ObjectFingers.begin(); | |
vRotationCur.clear(); | |
for(it; it!=ObjectFingers.end();it++) | |
{ | |
vRotationCur.push_back(Vector3(it->second.cvec.x,it->second.cvec.y,it->second.id)); | |
} | |
} | |
} | |
void OgreListener::nx_interaction(){ | |
if(iCurrentMode==INIT_STATE){ | |
vRotationCur.clear(); | |
vMoveCur = Vector2::ZERO; | |
vMovePrev = Vector2::ZERO; | |
vRotationPrev.clear(); | |
}else if(iCurrentMode==TRANSLATION){ | |
// tx, ty avec vMoveCur | |
translate(); | |
// update | |
vMovePrev = vMoveCur; | |
// reset | |
vRotationPrev.clear(); | |
}else if(iCurrentMode==TOUCH_2){ | |
// tz, rx, ry, rz | |
if(vRotationPrev.size() == vRotationCur.size()) | |
{ | |
direct3D_rotation_z(); | |
}else{ | |
init_direct3D(); | |
} | |
// update | |
vRotationPrev = vRotationCur; | |
// reset | |
vMovePrev = Vector2::ZERO; | |
}else if(iCurrentMode==TOUCH_3){ | |
// tx, ty, tz, rx, ry, rz | |
if(vRotationPrev.size() == vRotationCur.size()) | |
{ | |
direct3D_full(); | |
}else{ | |
init_direct3D(); | |
} | |
// update | |
vRotationPrev = vRotationCur; | |
// reset | |
vMovePrev = Vector2::ZERO; | |
} | |
moveObject(); | |
} | |
//------------------------------ | |
// INTERACTION SUB-FUNCTION | |
//------------------------------ | |
void OgreListener::init_offset(){ | |
Vector3 vectorResult; | |
int picking = mini_picking(vMoveCur,vectorResult); | |
if(picking==PICKING_OK) | |
{ | |
vOffset = vectorResult; // Store the exact point picked ! | |
} | |
} | |
// handle 2DOF translation | |
void OgreListener::translate(){ | |
if(vMovePrev==Vector2::ZERO) | |
{ | |
init_offset(); // if we just start interaction, init ! | |
}else if(vMoveCur != vMovePrev){ | |
// I used a planed defined with a Vector3 | |
Vector3 vPlanCamera = mCamNode->getOrientation()*Vector3(0,0,-1); | |
// and a point (where we touched the object in init_offset) | |
Plane plan(vPlanCamera,vOffset); | |
Vector3 vCur; | |
if(plane_picking(vMoveCur,plan,vCur)) | |
{ | |
// translation with 2DOF | |
vectorTranslation = (vCur-vOffset); | |
// updating the offset | |
vOffset = vCur; | |
} | |
} | |
} | |
// handle pitch and roll for sticky tools | |
void OgreListener::shallow_pitch(){ | |
if(vRollPrev!=Vector2::ZERO && vRollCur != vRollPrev) | |
{ | |
real roll = (vRollCur.x - vRollPrev.x)*v3K1; | |
real pitch = (vRollCur.y - vRollPrev.y)*v3K2; | |
Quaternion qY,qX; | |
if(roll!=0.0) qX = Quaternion(Radian(roll),mCamNode->getOrientation()*Vector3(0,1,0)); | |
if(pitch!=0.0) qY = Quaternion(Radian(pitch),mCamNode->getOrientation()*Vector3(1,0,0)); | |
quatRotation = qX * qY * quatRotation; | |
//quatRotation = (quatRotation.operator +(qX)).operator +(qY); | |
} | |
} | |
// handle translation among the third dimension | |
void OgreListener::z_translate(){ | |
if(vZPrev!=Vector2::ZERO && vZCur!=vZPrev){ | |
Vector2 vDiff = vZCur - vZPrev; | |
real interpolate_z = itp_z.Interpolate(vDiff.y) * vDiff.y; // we used an optional interpolation | |
// We want to object to stay under the finger, we thus will move it among the ray defined by vMoveCur (position of the translation finger) | |
Real impact = 0; | |
Ray mouseRay = mSceneMgr->getCamera("Camera")->getCameraToViewportRay(vMoveCur.x,vMoveCur.y); | |
mRaySceneQuery->setQueryMask(OK_MASK); | |
mRaySceneQuery->setRay(mouseRay); | |
mRaySceneQuery->setSortByDistance(true); | |
RaySceneQueryResult &result = mRaySceneQuery->execute(); | |
RaySceneQueryResult::iterator itr = result.begin(); | |
while (itr != result.end() && !(IsNamePickedOK(itr->movable->getName()))) | |
{ | |
itr++; | |
} | |
if (itr != result.end() && itr->movable) | |
{ | |
impact = itr->distance; | |
} | |
if (impact!=0) | |
{ | |
// To have our translation vector, we proceed to a difference | |
Vector3 oldpos = mouseRay.getPoint(impact); // Current point | |
Vector3 newpos = mouseRay.getPoint(impact + interpolate_z); // Current point + z_translation | |
Vector3 diff = oldpos-newpos; // we obtain a distance among the ray | |
vectorTranslation += diff; // that we add to vectorTranslation | |
} | |
} | |
} | |
// init the solver | |
void OgreListener::init_direct3D(){ | |
mapPoint3DToMatch.clear(); | |
mapPoint2D.clear(); | |
// We will pick every finger so as to match 2D point with 3D points | |
int nbFingerOK = 0; | |
int picking; | |
Vector3 vPicked; | |
Vector3 vFingerCur; | |
std::list<Vector3>::iterator itcur = vRotationCur.begin(); | |
for(itcur; itcur!=vRotationCur.end();itcur++) | |
{ | |
vFingerCur = (*itcur); | |
picking = mini_picking(Vector2(vFingerCur.x,vFingerCur.y),vPicked); | |
if(picking == PICKING_OK) | |
{ | |
mapPoint3DToMatch.insert(pair<int,Vector3>(vFingerCur.z,vPicked)); // id of the finger, with 3D position of the object in the 3D scene | |
mapPoint2D.insert(pair<int,Vector2>(vFingerCur.z,Vector2(vFingerCur.x,vFingerCur.y))); // id of the finger, with 2D position on the screen | |
nbFingerOK++; | |
} | |
} | |
iNbFingerPicked = nbFingerOK; | |
} | |
// Use of the solver for 4 DOF | |
void OgreListener::sticky_4dof(){ | |
// They are the same size (cf _interaction) proceed if one has moved | |
if(vRotationCur != vRotationPrev) | |
{ | |
int nbFingerOK = 0; | |
// First, update the map2D et map3D ... | |
Vector3 vPicked; | |
Vector2 vFingerCur; | |
Vector2 vFingerPrev; | |
Vector2 vSommeFingerRotationPrev = Vector2::ZERO; | |
std::list<Vector3>::iterator itprev = vRotationPrev.begin(); | |
std::list<Vector3>::iterator itcur = vRotationCur.begin(); | |
// for every finger | |
for(itprev; itprev!=vRotationPrev.end();itprev++) | |
{ | |
vFingerPrev = Vector2((*itprev).x,(*itprev).y); | |
vFingerCur = Vector2((*itcur).x,(*itcur).y); | |
int fID = (*itprev).z; | |
// We will save the total of movement for later | |
vSommeFingerRotationPrev = vSommeFingerRotationPrev + vFingerPrev; | |
// update of the map2D and map3D if picking OK | |
std::map<int,Vector2>::iterator it2D = mapPoint2D.find(fID); | |
std::map<int,Vector3>::iterator it3D = mapPoint3DToMatch.find(fID); | |
if(it2D != mapPoint2D.end()){ | |
// if picking OK | |
if(it3D != mapPoint3DToMatch.end() && mini_picking(it2D->second,vPicked)==PICKING_OK ) | |
{ | |
// then update map3D | |
it3D->second = vPicked; | |
} | |
// update map2D | |
it2D->second = vFingerCur; | |
} | |
itcur++; | |
} | |
// If we have at least two fingers | |
if (mapPoint2D.size()>1) | |
{ | |
vCentreObject = selectedNode->getPosition(); | |
// problem size | |
int n = mapPoint2D.size(); | |
// 1 - Compute the center of the previous fingers. | |
Vector2 vPrevCentre2D = (vSommeFingerRotationPrev)/n; | |
// 2 - Compute the sum of the displacements from the center. | |
Vector2 displacement = Vector2::ZERO; | |
std::map<int,Finger>::iterator it = ObjectFingers.begin(); | |
for(it; it!=ObjectFingers.end();it++) | |
{ | |
Finger *temp = &(it->second); | |
displacement = displacement + (Vector2(temp->cvec.x,temp->cvec.y)-vPrevCentre2D); | |
} | |
// will store the minimization via extern function | |
double *x = (double *)malloc(n*2*sizeof(double)); | |
for (int i = 0; i < n*2; i++) | |
x[i] = 0.0; | |
// number of DOF to solve, here tx, ty, tz, rz | |
int m = 4; | |
// initial value of our parameters, to guide the solver in the right way | |
double p[4] = { 0.0, 0.0, 0.0, 0.0}; | |
if (displacement.x < 0.0) | |
{ | |
p[0] = -0.01; | |
}else{ | |
p[0] = 0.01; | |
} | |
if (displacement.y < 0.0) | |
{ | |
p[1] = -0.01; | |
}else{ | |
p[1] = 0.01; | |
} | |
// Allocate some data structure for levenberg. | |
double opts[LM_OPTS_SZ]; | |
opts[0] = LM_INIT_MU; | |
opts[1] = 1E-15; | |
opts[2] = 1E-15; | |
opts[3] = 1E-20; | |
opts[4] = LM_DIFF_DELTA; | |
double info[LM_INFO_SZ]; | |
// main call for the solver, it will use the diff2D_4DOF function defined globally | |
int ret = dlevmar_dif(diff2D_4DOF, p, x, m, n*2, 1000, opts, info, NULL, NULL, NULL); | |
// if OK | |
if ((fabs(info[6] -1.0) < 0.00001) || (fabs(info[6] - 2.0) < 0.00001)) | |
{ | |
// retry value from solver and adjust vectorTranslation and quatRotation | |
Vector3 txy = Vector3(p[0],p[1],0); | |
Vector3 scale = vCentreObject- mCamera->getPositionForViewUpdate(); | |
scale = scale * p[2]; | |
vectorTranslation = txy + scale; | |
quatRotation = Quaternion(Radian(p[3]),mCamera->getOrientationForViewUpdate()*Vector3 (0,0,1)); | |
// Update the map3D point with the rotation : necessary when overconstrained and finger not on the object anymore | |
std::map<int,Vector3>::iterator it3D = mapPoint3DToMatch.begin(); | |
for(it3D;it3D!=mapPoint3DToMatch.end();it3D++){ | |
Vector3 vPoint3D = it3D->second; | |
it3D->second = quatRotation*(vPoint3D-vCentreObject) + vCentreObject + vectorTranslation; | |
} | |
} | |
// Cleaning stuff | |
free(x); | |
} | |
} | |
} | |
// Cf sticky_4dof, exact same structure | |
void OgreListener::direct3D_rotation(){ | |
if(vRotationCur != vRotationPrev) | |
{ | |
int nbFingerOK = 0; | |
// On va mettre à jour les positions 2D si nécessaire et calculer le déplacement avec prev ! | |
Vector3 vPicked; | |
Vector2 vFingerCur; | |
Vector2 vFingerPrev; | |
Vector2 vSommeFingerRotationPrev = Vector2::ZERO; | |
std::list<Vector3>::iterator itprev = vRotationPrev.begin(); | |
std::list<Vector3>::iterator itcur = vRotationCur.begin(); | |
for(itprev; itprev!=vRotationPrev.end();itprev++) | |
{ | |
vFingerPrev = Vector2((*itprev).x,(*itprev).y); | |
vFingerCur = Vector2((*itcur).x,(*itcur).y); | |
int fID = (*itprev).z; | |
// Calcul prev | |
vSommeFingerRotationPrev = vSommeFingerRotationPrev + vFingerPrev; | |
// Mise à jour coordonnée 2D et si picking hop on met à jour | |
std::map<int,Vector2>::iterator it2D = mapPoint2D.find(fID); | |
std::map<int,Vector3>::iterator it3D = mapPoint3DToMatch.find(fID); | |
// Si la fonction find a bien finder et | |
if(it2D != mapPoint2D.end()){ | |
// Si picking ok | |
if(it3D != mapPoint3DToMatch.end() && mini_picking(it2D->second,vPicked)==PICKING_OK ) | |
{ | |
// alors on met à jour les point3D associé avec le point2D prev! | |
it3D->second = vPicked; | |
} | |
// On met à jour le point 2D avec la valeur courante | |
it2D->second = vFingerCur; | |
} | |
itcur++; | |
} | |
// Si OK | |
if (mapPoint2D.size()>1) | |
{ | |
// Centre de rotation : centre Objet | |
vCentreObject = selectedNode->getPosition(); | |
// taille du problème : ici nombre de doigts | |
int n = mapPoint2D.size(); | |
// 1 - Compute the center of the previous fingers. | |
Vector2 vPrevCentre2D = (vSommeFingerRotationPrev)/n; | |
// 2 - Compute the sum of the displacements from the center. | |
Vector2 displacement = Vector2::ZERO; | |
std::map<int,Finger>::iterator it = ObjectFingers.begin(); | |
for(it; it!=ObjectFingers.end();it++) | |
{ | |
Finger *temp = &(it->second); | |
displacement = displacement + (Vector2(temp->cvec.x,temp->cvec.y)-vPrevCentre2D); | |
} | |
// Tableau pour ce qu'on va calculer | |
double *x = (double *)malloc(n*2*sizeof(double)); | |
for (int i = 0; i < n*2; i++) | |
x[i] = 0.0; | |
// (ex, ey, ez) | |
int m = 3; | |
double p[3] = { 0.0, 0.0, 0.0}; | |
if (displacement.x < 0.0) | |
{ | |
p[0] = -0.01; | |
}else{ | |
p[0] = 0.01; | |
} | |
if (displacement.y < 0.0) | |
{ | |
p[1] = -0.01; | |
}else{ | |
p[1] = 0.01; | |
} | |
double opts[LM_OPTS_SZ]; | |
opts[0] = LM_INIT_MU; | |
opts[1] = 1E-17; | |
opts[2] = 1E-17; | |
opts[3] = 1E-17; | |
opts[4] = LM_DIFF_DELTA; | |
double info[LM_INFO_SZ]; | |
int ret = dlevmar_dif(diff2D_3DOF, p, x, m, n*2, 1000, opts, info, NULL, NULL, NULL); | |
// Si OK | |
if ((fabs(info[6] -1.0) < 0.00001) || (fabs(info[6] - 2.0) < 0.00001)) | |
{ | |
Quaternion qRot; | |
qRot.x = p[0]; | |
qRot.y = p[1]; | |
qRot.z = p[2]; | |
qRot.normalise(); | |
quatRotation = qRot; | |
// Mise à jour des points 3D en tenant compte de la rotation ! | |
std::map<int,Vector3>::iterator it3D = mapPoint3DToMatch.begin(); | |
for(it3D;it3D!=mapPoint3DToMatch.end();it3D++){ | |
Vector3 vPoint3D = it3D->second; | |
it3D->second = qRot*(vPoint3D-vCentreObject) + vCentreObject; | |
} | |
} | |
// Cleaning stuff | |
free(x); | |
} | |
} | |
} | |
// Cf sticky_4dof, exact same structure | |
void OgreListener::direct3D_rotation_z(){ | |
if(vRotationCur != vRotationPrev) | |
{ | |
int nbFingerOK = 0; | |
// On va mettre à jour les positions 2D si nécessaire et calculer le déplacement avec prev ! | |
Vector3 vPicked; | |
Vector2 vFingerCur; | |
Vector2 vFingerPrev; | |
Vector2 vSommeFingerRotationPrev = Vector2::ZERO; | |
std::list<Vector3>::iterator itprev = vRotationPrev.begin(); | |
std::list<Vector3>::iterator itcur = vRotationCur.begin(); | |
for(itprev; itprev!=vRotationPrev.end();itprev++) | |
{ | |
vFingerPrev = Vector2((*itprev).x,(*itprev).y); | |
vFingerCur = Vector2((*itcur).x,(*itcur).y); | |
int fID = (*itprev).z; | |
// Calcul prev | |
vSommeFingerRotationPrev = vSommeFingerRotationPrev + vFingerPrev; | |
// Mise à jour coordonnée 2D et si picking hop on met à jour | |
std::map<int,Vector2>::iterator it2D = mapPoint2D.find(fID); | |
std::map<int,Vector3>::iterator it3D = mapPoint3DToMatch.find(fID); | |
// Si la fonction find a bien finder et | |
if(it2D != mapPoint2D.end()){ | |
// Si picking ok | |
if(it3D != mapPoint3DToMatch.end() && mini_picking(it2D->second,vPicked)==PICKING_OK ) | |
{ | |
// alors on met à jour les point3D associé avec le point2D prev! | |
it3D->second = vPicked; | |
} | |
// On met à jour le point 2D avec la valeur courante | |
it2D->second = vFingerCur; | |
} | |
itcur++; | |
} | |
// Si OK | |
if (mapPoint2D.size()>1) | |
{ | |
// Centre de rotation : centre Objet | |
vCentreObject = selectedNode->getPosition(); | |
// taille du problème : ici nombre de doigts | |
int n = mapPoint2D.size(); | |
// 1 - Compute the center of the previous fingers. | |
Vector2 vPrevCentre2D = (vSommeFingerRotationPrev)/n; | |
// 2 - Compute the sum of the displacements from the center. | |
Vector2 displacement = Vector2::ZERO; | |
std::map<int,Finger>::iterator it = ObjectFingers.begin(); | |
for(it; it!=ObjectFingers.end();it++) | |
{ | |
Finger *temp = &(it->second); | |
displacement = displacement + (Vector2(temp->cvec.x,temp->cvec.y)-vPrevCentre2D); | |
} | |
// Tableau pour ce qu'on va calculer | |
double *x = (double *)malloc(n*2*sizeof(double)); | |
for (int i = 0; i < n*2; i++) | |
x[i] = 0.0; | |
// (tz, ex, ey, ez) | |
int m = 3; | |
double p[4] = { 0.0, 0.0, 0.0, 0.0}; | |
if (displacement.x < 0.0) | |
{ | |
p[1] = -0.01; | |
}else{ | |
p[1] = 0.01; | |
} | |
if (displacement.y < 0.0) | |
{ | |
p[2] = -0.01; | |
}else{ | |
p[2] = 0.01; | |
} | |
double opts[LM_OPTS_SZ]; | |
opts[0] = LM_INIT_MU; | |
opts[1] = 1E-15; | |
opts[2] = 1E-15; | |
opts[3] = 1E-20; | |
opts[4] = LM_DIFF_DELTA; | |
double info[LM_INFO_SZ]; | |
int ret = dlevmar_dif(diff2D_4DOFz, p, x, m, n*2, 1000, opts, info, NULL, NULL, NULL); | |
// Si OK | |
if ((fabs(info[6] -1.0) < 0.00001) || (fabs(info[6] - 2.0) < 0.00001)) | |
{ | |
Vector3 deltaPos = vCentreObject- mCamera->getPositionForViewUpdate(); | |
vectorTranslation = deltaPos * p[0]; | |
Quaternion qRot; | |
qRot.x = p[1]; | |
qRot.y = p[2]; | |
qRot.z = p[3]; | |
qRot.normalise(); | |
quatRotation = qRot; | |
// Mise à jour des points 3D en tenant compte de la rotation ! | |
std::map<int,Vector3>::iterator it3D = mapPoint3DToMatch.begin(); | |
for(it3D;it3D!=mapPoint3DToMatch.end();it3D++){ | |
Vector3 vPoint3D = it3D->second; | |
it3D->second = quatRotation*(vPoint3D-vCentreObject) + vCentreObject + vectorTranslation; | |
} | |
} | |
// Cleaning stuff | |
free(x); | |
} | |
} | |
} | |
// Cf sticky_4dof, exact same structure | |
void OgreListener::direct3D_full(){ | |
if(vRotationCur != vRotationPrev) | |
{ | |
int nbFingerOK = 0; | |
// On va mettre à jour les positions 2D si nécessaire et calculer le déplacement avec prev ! | |
Vector3 vPicked; | |
Vector2 vFingerCur; | |
Vector2 vFingerPrev; | |
Vector2 vSommeFingerRotationPrev = Vector2::ZERO; | |
std::list<Vector3>::iterator itprev = vRotationPrev.begin(); | |
std::list<Vector3>::iterator itcur = vRotationCur.begin(); | |
for(itprev; itprev!=vRotationPrev.end();itprev++) | |
{ | |
vFingerPrev = Vector2((*itprev).x,(*itprev).y); | |
vFingerCur = Vector2((*itcur).x,(*itcur).y); | |
int fID = (*itprev).z; | |
// Calcul prev | |
vSommeFingerRotationPrev = vSommeFingerRotationPrev + vFingerPrev; | |
// Mise à jour coordonnée 2D et si picking hop on met à jour | |
std::map<int,Vector2>::iterator it2D = mapPoint2D.find(fID); | |
std::map<int,Vector3>::iterator it3D = mapPoint3DToMatch.find(fID); | |
// Si la fonction find a bien finder et | |
if(it2D != mapPoint2D.end()){ | |
// Si picking ok | |
if(it3D != mapPoint3DToMatch.end() && mini_picking(it2D->second,vPicked)==PICKING_OK ) | |
{ | |
// alors on met à jour les point3D associé avec le point2D prev! | |
it3D->second = vPicked; | |
} | |
// On met à jour le point 2D avec la valeur courante | |
it2D->second = vFingerCur; | |
} | |
itcur++; | |
} | |
// Si OK | |
if (mapPoint2D.size()>2) | |
{ | |
// Centre de rotation : centre Objet | |
vCentreObject = selectedNode->getPosition(); | |
// taille du problème : ici nombre de doigts | |
int n = mapPoint2D.size(); | |
// 1 - Compute the center of the previous fingers. | |
Vector2 vPrevCentre2D = (vSommeFingerRotationPrev)/n; | |
// 2 - Compute the sum of the displacements from the center. | |
Vector2 displacement = Vector2::ZERO; | |
std::map<int,Finger>::iterator it = ObjectFingers.begin(); | |
for(it; it!=ObjectFingers.end();it++) | |
{ | |
Finger *temp = &(it->second); | |
displacement = displacement + (Vector2(temp->cvec.x,temp->cvec.y)-vPrevCentre2D); | |
} | |
// Tableau pour ce qu'on va calculer | |
double *x = (double *)malloc(n*2*sizeof(double)); | |
for (int i = 0; i < n*2; i++) | |
x[i] = 0.0; | |
// (tx,ty,tz, ex, ey, ez) | |
int m = 6; | |
double p[6] = { 0.0, 0.0, 0.1, 0.1 , 0.1, 0.1}; | |
if (displacement.x < 0.0) | |
{ | |
p[0] = -0.01; | |
}else{ | |
p[0] = 0.01; | |
} | |
if (displacement.y < 0.0) | |
{ | |
p[1] = -0.01; | |
}else{ | |
p[1] = 0.01; | |
} | |
double opts[LM_OPTS_SZ]; | |
opts[0] = LM_INIT_MU; | |
opts[1] = 1E-15; | |
opts[2] = 1E-15; | |
opts[3] = 1E-20; | |
opts[4] = LM_DIFF_DELTA; | |
double info[LM_INFO_SZ]; | |
int ret = dlevmar_dif(diff2D_6DOF, p, x, m, n*2, 1000, opts, info, NULL, NULL, NULL); | |
// Si OK | |
if ((fabs(info[6] -1.0) < 0.00001) || (fabs(info[6] - 2.0) < 0.00001)) | |
{ | |
Quaternion qRot; | |
qRot.x = p[3]; | |
qRot.y = p[4]; | |
qRot.z = p[5]; | |
qRot.normalise(); | |
quatRotation = qRot; | |
vectorTranslation = mCamera->getOrientationForViewUpdate() * Vector3 (p[0],p[1],p[2]); | |
// Mise à jour des points 3D en tenant compte de la rotation ! | |
std::map<int,Vector3>::iterator it3D = mapPoint3DToMatch.begin(); | |
for(it3D;it3D!=mapPoint3DToMatch.end();it3D++){ | |
Vector3 vPoint3D = it3D->second; | |
it3D->second = quatRotation*(vPoint3D-vCentreObject) + vCentreObject + vectorTranslation; | |
} | |
} | |
// Cleaning stuff | |
free(x); | |
} | |
} | |
} | |
//------------------------------ | |
// OBJECT DISPLACEMENT | |
//------------------------------ | |
void OgreListener::moveObject(){ | |
// TO DO, switch to 4*4 matrix | |
if(selectedNode != NULL) | |
{ | |
Quaternion prevQuat = selectedNode->getOrientation(); | |
Vector3 prevTrans = selectedNode->getPosition(); | |
vCentreObject = selectedNode->getPosition(); | |
if(quatRotation!=Quaternion::IDENTITY) | |
{ | |
// handle if the center of rotation is different from center of the object | |
Vector3 vTranslation = vCentreRotation - vCentreObject; | |
if(vCentreRotation!=Vector3::ZERO) | |
{ | |
// On sait qu'on dois tourner autour de centreRotation | |
// Calculons le déplacement que ce point fait | |
Vector3 newPos = quatRotation*vTranslation; | |
selectedNode->rotate(quatRotation,Node::TS_WORLD); | |
// maintenant le point de rotation à bouger, on le ramène à sa place en faisant | |
selectedNode->translate(vCentreRotation-(newPos+vCentreObject)); | |
vCentreRotation = Vector3::ZERO; | |
}else{ | |
selectedNode->rotate(quatRotation,Node::TS_WORLD); | |
} | |
quatRotation = Quaternion::IDENTITY; | |
} | |
if(vectorTranslation!=Vector3::ZERO) | |
{ | |
selectedNode->translate(vectorTranslation); | |
Vector3 pos = selectedNode->getPosition(); | |
if(vectorTranslation.z != 0.0) // if we change the depth, re init offset ! | |
{ | |
init_offset(); | |
} | |
vectorTranslation = Vector3::ZERO; | |
} | |
} | |
} | |
//------------------------------ | |
// SOLVER FUNCTION (EXTERN) | |
//------------------------------ | |
/* The following function measures the error between the current 3D points and | |
the reprojected 2D points considering the p vetor. */ | |
/* p is the std::vector of values we are looking for (translations and rotations). | |
hx is the result of the computation done by the function. | |
n is the number of values for hx. */ | |
void diff2D_6DOF(double *p, double *hx, int m, int n, void *adata){ | |
/* Retrieve the translation and the rotation from the p std::vector. */ | |
/* Translation values are the first 3 values in the p std::vector. */ | |
Vector3 deltaPos; | |
deltaPos.x = p[0]; | |
deltaPos.y = p[1]; | |
deltaPos.z = p[2]; | |
deltaPos = gmCamera->getOrientationForViewUpdate() * deltaPos; | |
/* Quaternion x, y, z are the 3 last values of the p std::vector. */ | |
Quaternion deltaQuat; | |
deltaQuat.x = p[3]; | |
deltaQuat.y = p[4]; | |
deltaQuat.z = p[5]; | |
deltaQuat.normalise(); | |
/* Save the current transformations, then apply the current transformations from the p std::vector, | |
project and finally restaure the initial transformations. */ | |
/* For each world point, compute the projected point, depending on the input parameters p. */ | |
std::map<int,Vector3>::iterator itV3; | |
std::map<int,Vector2>::iterator itV2; | |
int i=0; | |
for (itV3=mapPoint3DToMatch.begin();itV3!=mapPoint3DToMatch.end();itV3++) | |
{ | |
Vector3 v3Prev = (*itV3).second; | |
itV2 = mapPoint2D.find((*itV3).first); | |
Vector2 v2DCur = Vector2::ZERO; | |
if(itV2 != mapPoint2D.end()){ | |
v2DCur = (*itV2).second; | |
}else{ | |
cout << "erreur diff2D_6DOF" << endl; | |
return; | |
} | |
/* Apply tr & rotate to V3Prev */ | |
Matrix3 temp; | |
deltaQuat.ToRotationMatrix(temp); | |
Matrix4 mat(temp); | |
mat.setTrans(vCentreObject+deltaPos); | |
Vector3 V3DOK = mat*(v3Prev-vCentreObject); | |
/* Project the world points to the screen space, using transformations defined by the p std::vector. */ | |
Vector2 v2DTest; | |
bool proj = get2DCoord(gmCamera,V3DOK,v2DTest); | |
/* Compute the result, ie the difference between fingers 2D points and | |
the computed 2D points considering the p std::vector. */ | |
hx[i*2] = (v2DTest.x - v2DCur.x); | |
hx[i*2 + 1] = (v2DTest.y - v2DCur.y); | |
/* Update pointeurs */ | |
i++; | |
itV2++; | |
} | |
} | |
void diff2D_4DOFz(double *p, double *hx, int m, int n, void *adata){ | |
/* Retrieve the translation and the rotation from the p std::vector. */ | |
Vector3 deltaPos = vCentreObject - gmCamera->getPositionForViewUpdate(); | |
/* Translation values are the first 3 values in the p std::vector. */ | |
deltaPos = p[0]*deltaPos; | |
/* Quaternion x, y, z are the 3 last values of the p std::vector. */ | |
Quaternion deltaQuat; | |
deltaQuat.x = p[1]; | |
deltaQuat.y = p[2]; | |
deltaQuat.z = p[3]; | |
deltaQuat.normalise(); | |
/* Save the current transformations, then apply the current transformations from the p std::vector, | |
project and finally restaure the initial transformations. */ | |
/* For each world point, compute the projected point, depending on the input parameters p. */ | |
std::map<int,Vector3>::iterator itV3; | |
std::map<int,Vector2>::iterator itV2; | |
int i=0; | |
for (itV3=mapPoint3DToMatch.begin();itV3!=mapPoint3DToMatch.end();itV3++) | |
{ | |
Vector3 v3Prev = (*itV3).second; | |
itV2 = mapPoint2D.find((*itV3).first); | |
Vector2 v2DCur = Vector2::ZERO; | |
if(itV2 != mapPoint2D.end()){ | |
v2DCur = (*itV2).second; | |
}else{ | |
cout << "erreur diff2D_4DOFz" << endl; | |
return; | |
} | |
/* Appliquer la transformation tr et rotate à V3Prev */ | |
Matrix3 temp; | |
deltaQuat.ToRotationMatrix(temp); | |
Matrix4 mat(temp); | |
mat.setTrans(vCentreObject+deltaPos); | |
Vector3 V3DOK = mat*(v3Prev-vCentreObject); | |
/* Project the world points to the screen space, using transformations defined by the p std::vector. */ | |
Vector2 v2DTest; | |
bool proj = get2DCoord(gmCamera,V3DOK,v2DTest); | |
/* Compute the result, ie the difference between fingers 2D points and | |
the computed 2D points considering the p std::vector. */ | |
hx[i*2] = (v2DTest.x - v2DCur.x); | |
hx[i*2 + 1] = (v2DTest.y - v2DCur.y); | |
/* Update pointeurs */ | |
i++; | |
itV2++; | |
} | |
} | |
void diff2D_4DOF(double *p, double *hx, int m, int n, void *adata){ | |
/* Retrieve the translation and the rotation from the p std::vector. */ | |
Vector3 deltaPos; | |
Vector3 txy = Vector3(p[0],p[1],0); | |
Vector3 scale = vCentreObject - gmCamera->getPositionForViewUpdate(); | |
scale = scale * p[2]; | |
deltaPos = txy + scale; | |
/* Translation values are the first 3 values in the p std::vector. */ | |
/* Quaternion x, y, z are the 3 last values of the p std::vector. */ | |
Quaternion deltaQuat(Radian(p[3]),gmCamera->getOrientationForViewUpdate()*Vector3(0,0,1)); | |
/* Save the current transformations, then apply the current transformations from the p std::vector, | |
project and finally restaure the initial transformations. */ | |
/* For each world point, compute the projected point, depending on the input parameters p. */ | |
std::map<int,Vector3>::iterator itV3; | |
std::map<int,Vector2>::iterator itV2; | |
int i=0; | |
for (itV3=mapPoint3DToMatch.begin();itV3!=mapPoint3DToMatch.end();itV3++) | |
{ | |
Vector3 v3Prev = (*itV3).second; | |
itV2 = mapPoint2D.find((*itV3).first); | |
Vector2 v2DCur = Vector2::ZERO; | |
if(itV2 != mapPoint2D.end()){ | |
v2DCur = (*itV2).second; | |
}else{ | |
cout << "erreur diff2D_4DOF" << endl; | |
return; | |
} | |
/* Appliquer la transformation tr et rotate à V3Prev */ | |
Matrix3 temp; | |
deltaQuat.ToRotationMatrix(temp); | |
Matrix4 mat(temp); | |
mat.setTrans(vCentreObject+deltaPos); | |
Vector3 V3DOK = mat*(v3Prev-vCentreObject); | |
/* Project the world points to the screen space, using transformations defined by the p std::vector. */ | |
Vector2 v2DTest; | |
bool proj = get2DCoord(gmCamera,V3DOK,v2DTest); | |
/* Compute the result, ie the difference between fingers 2D points and | |
the computed 2D points considering the p std::vector. */ | |
hx[i*2] = (v2DTest.x - v2DCur.x); | |
hx[i*2 + 1] = (v2DTest.y - v2DCur.y); | |
/* Update pointeurs */ | |
i++; | |
itV2++; | |
} | |
} | |
void diff2D_3DOF(double *p, double *hx, int m, int n, void *adata){ | |
/* Retrieve the translation and the rotation from the p std::vector. */ | |
/* Translation values are the first 3 values in the p std::vector. */ | |
Quaternion deltaQuat; | |
deltaQuat.x = p[0]; | |
deltaQuat.y = p[1]; | |
deltaQuat.z = p[2]; | |
deltaQuat.normalise(); | |
/* Save the current transformations, then apply the current transformations from the p std::vector, | |
project and finally restaure the initial transformations. */ | |
/* For each world point, compute the projected point, depending on the input parameters p. */ | |
std::map<int,Vector3>::iterator itV3; | |
std::map<int,Vector2>::iterator itV2; | |
int i=0; | |
for (itV3=mapPoint3DToMatch.begin();itV3!=mapPoint3DToMatch.end();itV3++) | |
{ | |
Vector3 v3Prev = (*itV3).second; | |
itV2 = mapPoint2D.find((*itV3).first); | |
Vector2 v2DCur = Vector2::ZERO; | |
if(itV2 != mapPoint2D.end()){ | |
v2DCur = (*itV2).second; | |
}else{ | |
cout << "erreur diff2D_3DOF" << endl; | |
return; | |
} | |
/* Appliquer la transformation tr et rotate à V3Prev */ | |
/* | |
Matrix3 temp; | |
deltaQuat.ToRotationMatrix(temp); | |
Matrix4 mat(temp); | |
mat.setTrans(vCentreObject); | |
*/ | |
Vector3 V3DOK = deltaQuat*(v3Prev-vCentreObject) + vCentreObject; | |
/* Project the world points to the screen space, using transformations defined by the p std::vector. */ | |
Vector2 v2DTest; | |
bool proj = get2DCoord(gmCamera,V3DOK,v2DTest); | |
/* Compute the result, ie the difference between fingers 2D points and | |
the computed 2D points considering the p std::vector. */ | |
hx[i*2] = (v2DTest.x - v2DCur.x); | |
hx[i*2 + 1] = (v2DTest.y - v2DCur.y); | |
/* Update pointeurs */ | |
i++; | |
itV2++; | |
} | |
} | |
bool get2DCoordMatrix(Matrix4 view, Matrix4 proj, Vector3 pos3D, Vector2 &pos2D){ | |
Vector3 eyeSpacePos = view * pos3D; | |
Real x,y; | |
// z < 0 means in front of cam | |
if (eyeSpacePos.z < 0) { | |
// calculate projected pos | |
Vector3 screenSpacePos = proj * eyeSpacePos; | |
x = screenSpacePos.x; | |
y = screenSpacePos.y; | |
// Coming back to [0,1] of the screen | |
x = (x+1)/2; | |
y = (-y+1)/2; | |
pos2D = Vector2(x,y); | |
return true; | |
} else { | |
x = (-eyeSpacePos.x > 0) ? -1 : 1; | |
y = (-eyeSpacePos.y > 0) ? -1 : 1; | |
return false; | |
} | |
} | |
bool get2DCoord (Camera* cam,Vector3 pos3D, Vector2 &pos2D){ | |
Vector3 eyeSpacePos = cam->getViewMatrix(true) * pos3D; | |
Real x,y; | |
// z < 0 means in front of cam | |
if (eyeSpacePos.z < 0) { | |
// calculate projected pos | |
Vector3 screenSpacePos = cam->getProjectionMatrix() * eyeSpacePos; | |
x = screenSpacePos.x; | |
y = screenSpacePos.y; | |
// Coming back to [0,1] of the screen | |
x = (x+1)/2; | |
y = (-y+1)/2; | |
pos2D = Vector2(x,y); | |
return true; | |
} else { | |
x = (-eyeSpacePos.x > 0) ? -1 : 1; | |
y = (-eyeSpacePos.y > 0) ? -1 : 1; | |
return false; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef INCLUDED_LISTENER_H | |
#define INCLUDED_LISTENER_H | |
#pragma once | |
/****************** | |
Basic Ogre | |
*******************/ | |
#include <Ogre.h> | |
#include <OIS/OIS.h> | |
/****************** | |
My files | |
*******************/ | |
#include "lock.h" // Class to handle mutex | |
#include "finger.h" // To store finger information (basically current position as Vector2) | |
#include "lm.h" // this comes from http://www.ics.forth.gr/~lourakis/levmar/ | |
#include "mtlib.hpp" // it's our own tuio client, cooked to also handled win7. Should be released very soon ! | |
/****************** | |
Basic CEGUI | |
*******************/ | |
#include "CEGUI.h" | |
#include "RendererModules/Ogre/CEGUIOgreRenderer.h" | |
enum Mode // Mode used to handle interaction | |
{ | |
INIT_STATE, | |
NOTHING, | |
TRANSLATION, | |
TOUCH_2, | |
TOUCH_3, | |
Z_TRANSLATION, | |
COMBINED, | |
ROTATION, | |
}; | |
enum PickInfo // information returned with picking function | |
{ | |
NO_PICK = 0, | |
PICKING_OK = 1, | |
}; | |
enum Interaction // to have a more clear way of dealing with different techniques | |
{ | |
INTERACTION_DS3, | |
INTERACTION_STICKY, | |
INTERACTION_SCREENSPACE, | |
}; | |
enum QueryFlags // Specific to Ogre, to handle different group of picking | |
{ | |
OK_MASK = 1<<0, | |
KO_MASK = 1<<1, | |
TRACKBALL_MASK = 1<<2, | |
}; | |
using namespace Ogre; | |
/****************************************************************************************************************************** | |
Very important, those function are needed for the constraint solver (levmar) and have to be global | |
*******************************************************************************************************************************/ | |
bool get2DCoord (Camera* cam,Vector3 pos3D, Vector2 &pos2D); | |
void diff2D_6DOF(double *p, double *hx, int m, int n, void *adata); | |
void diff2D_4DOFz(double *p, double *hx, int m, int n, void *adata); | |
void diff2D_4DOF(double *p, double *hx, int m, int n, void *adata); | |
void diff2D_3DOF(double *p, double *hx, int m, int n, void *adata); | |
bool get2DCoordMatrix(Matrix4 view, Matrix4 proj, Vector3 pos3D, Vector2 &pos2D); | |
/************************************************************** | |
FrameListener : ogre specific | |
OIS::KeyListener : ogre specific | |
TouchListener : similar to TUIO client ! | |
**************************************************************/ | |
class OgreListener : public FrameListener, public OIS::KeyListener, public TouchListener | |
{ | |
public: | |
OgreListener(OIS::Keyboard *keyboard, Camera* cam, SceneManager *sceneMgr, RenderWindow* Window); | |
~OgreListener(); | |
//-------------------------------- | |
// BASIC STUFF | |
//-------------------------------- | |
bool keyPressed(const OIS::KeyEvent &e); | |
bool keyReleased(const OIS::KeyEvent &e); | |
bool frameStarted(const FrameEvent& evt); | |
private: | |
//------------------------------- | |
// OGRE | |
//------------------------------- | |
SceneManager *mSceneMgr; // The current SceneManager | |
SceneNode *mCamNode; // The SceneNode the camera is currently attached to | |
Camera *mCamera; | |
RenderWindow* mWindow; | |
OIS::Keyboard *mKeyboard; | |
bool mContinue; | |
//--------------------------- | |
// OBJECT MANIPULATION | |
//-------------------------- | |
SceneNode* selectedNode; | |
SceneNode* lastSelectedNode; | |
//------------------------------- | |
// TOUCH | |
//------------------------------- | |
std::map<int,Finger*> fingerMap; | |
CReadWriteLock multiTouchLock; | |
void on_touch_detect(TOUCH& args); | |
void on_touch_update(TOUCH& args); | |
void on_touch_release(TOUCH& args); | |
//------------------------------- | |
// CEGUI Event | |
//------------------------------ | |
void createCEGUIevent(); | |
bool quit(const CEGUI::EventArgs &e); | |
//----------------------------- | |
// INTERACTION MAIN FUNCTION | |
//----------------------------- | |
void updateInteraction(int iLastTouch, int iLastFinger, Finger *f); | |
void updateSelected(); | |
void ds3_gesture(int iLastTouch, int iLastFinger, Finger *f); | |
void ds3_mode(int iLastTouch, int iLastFinger, Finger *f); | |
void ds3_interaction(); | |
void sticky_gesture(int iLastTouch, int iLastFinger, Finger *f); | |
void sticky_mode(int iLastTouch, int iLastFinger, Finger *f); | |
void sticky_interaction(); | |
void nx_gesture(int iLastTouch, int iLastFinger, Finger *f); | |
void nx_mode(int iLastTouch, int iLastFinger, Finger *f); | |
void nx_interaction(); | |
void moveObject(); | |
//----------------------------- | |
// INTERACTION SUB FUNCTION | |
//----------------------------- | |
void init_offset(); | |
void translate(); | |
void shallow_pitch(); | |
void z_translate(); | |
void sticky_4dof(); | |
void init_direct3D(); | |
void direct3D_rotation(); | |
void direct3D_rotation_z(); | |
void direct3D_full(); | |
//---------------------------- | |
// OVERLAYS & FINGERPRINT | |
//---------------------------- | |
//Ogre2dManager* fingerprint; | |
void do_debuginfo(); | |
bool printFinger; | |
//------------------------------- | |
// PICKING FUNCTION | |
//------------------------------- | |
RaySceneQuery *mRaySceneQuery; | |
bool IsNamePickedOK(String name); | |
int basic_picking(Finger *fPick, Vector3 &Result); | |
int mini_picking(Vector2 pos, Vector3 &Result); | |
bool plane_picking(Vector2 pos, Plane plan, Vector3 &Result); | |
bool PickEntity(Ray &ray, | |
Entity ** result, | |
Vector3 &hitpoint, | |
Plane &hitplane, | |
Ogre::uint32 masque = OK_MASK); | |
void GetMeshInformationEx( const MeshPtr mesh, | |
size_t &vertex_count, | |
Vector3* &vertices, | |
size_t &index_count, | |
unsigned long* &indices, | |
const Vector3 &position, | |
const Quaternion &orient, | |
const Vector3 &scale); | |
//----------------------------- | |
// INTERACTION VARIABLE | |
//----------------------------- | |
int iNbFinger; // Used to count all the fingers | |
int iCurrentMode; // To store the mode we are in | |
int iCurrentTechnique; // ... | |
Finger *fZ; // To store indirect finger of z technique | |
Finger* fRoll; // To store indirect finger of sticky tools | |
std::map<int,Finger> ObjectFingers; // To store other fingers | |
// Interaction managment : vector that we will manipulate | |
Vector2 vMovePrev; | |
Vector2 vMoveCur; | |
Vector2 vYawCur; | |
Vector2 vYawPrev; | |
Vector2 vRollCur; | |
Vector2 vRollPrev; | |
Vector2 vZCur; | |
Vector2 vZPrev; | |
std::list<Vector3> vRotationPrev; | |
std::list<Vector3> vRotationCur; | |
Vector3 vOffset; // Offset Pyramide | |
int iNbFingerPicked; // gestion Screenspace | |
//----------------------------- | |
// OBJECT MOVEMENT VARIABLE | |
//----------------------------- | |
Vector3 vectorTranslation; // will store the translation to apply every frame | |
Quaternion quatRotation; // will store the rotation to apply every frame | |
//----------------------------- | |
// TECHNIQUE SPECIFIC VARIABLE | |
//----------------------------- | |
Real v3K1; // Facteur K1 Shallow Technique | |
Real v3K2; // Facteur K2 Shallow Technique | |
Real factorZ; | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment