1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-25 10:09:42 +00:00

Better mouse cursor tracking for the third axis.

This commit is contained in:
cc9cii 2014-11-10 20:37:07 +11:00
parent 1f73fae6ef
commit d7804974e8
2 changed files with 83 additions and 51 deletions

View file

@ -57,9 +57,9 @@ namespace CSVRender
MouseState::MouseState(WorldspaceWidget *parent) MouseState::MouseState(WorldspaceWidget *parent)
: mParent(parent), mPhysics(parent->getPhysics()), mSceneManager(parent->getSceneManager()) : mParent(parent), mPhysics(parent->getPhysics()), mSceneManager(parent->getSceneManager())
, mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) , mCurrentObj(""), mMouseState(Mouse_Default), mOldCursorPos(0,0), mMouseEventTimer(0)
, mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3())
, mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) , mOldMousePos(Ogre::Vector3()), mPlane(0)
, mColIndexPosX(0), mColIndexPosY(0), mColIndexPosZ(0), mIdTableModel(0) , mColIndexPosX(0), mColIndexPosY(0), mColIndexPosZ(0), mIdTableModel(0)
{ {
const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences();
@ -111,23 +111,24 @@ namespace CSVRender
} }
case Mouse_Drag: case Mouse_Drag:
{ {
if(event->pos() != mOldPos) // TODO: maybe don't update less than a quantum? if(event->pos() != mOldCursorPos) // TODO: maybe don't update less than a quantum?
{ {
mOldPos = event->pos(); mOldCursorPos = event->pos();
// ray test against the plane to provide feedback to the user the // ray test against the plane to provide feedback to the user the
// relative movement of the object on the x-y plane // relative movement of the object on the movement plane
std::pair<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane); std::pair<bool, Ogre::Vector3> planeResult = mousePosOnPlane(event->pos(), *mPlane);
if(planeResult.first) if(planeResult.first)
{ {
if(mGrabbedSceneNode != "") if(mGrabbedSceneNode != "")
{ {
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis(); Ogre::Vector3 pos = mOrigObjPos + (planeResult.second-mOrigMousePos);
Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset;
mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+planeResult.second-mOrigMousePos); mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos);
mCurrentMousePos = planeResult.second; mPhysics->moveSceneNodes(mGrabbedSceneNode, pos);
mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+planeResult.second-mOrigMousePos);
updateSceneWidgets(); updateSceneWidgets();
mOldMousePos = planeResult.second;
} }
} }
} }
@ -165,12 +166,11 @@ namespace CSVRender
// mouse in relation to the object position // mouse in relation to the object position
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis(); std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
mPlane->redefine(planeRes.first, result.second); mPlane->redefine(planeRes.first, result.second);
std::pair<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane); std::pair<bool, Ogre::Vector3> planeResult = mousePosOnPlane(event->pos(), *mPlane);
if(planeResult.first) if(planeResult.first)
{ {
mOrigMousePos = planeResult.second; mOrigMousePos = planeResult.second;
mCurrentMousePos = planeResult.second; mOldMousePos = planeResult.second;
mOffset = 0.0f;
} }
mOrigObjPos = mSceneManager->getSceneNode(mGrabbedSceneNode)->getPosition(); mOrigObjPos = mSceneManager->getSceneNode(mGrabbedSceneNode)->getPosition();
@ -206,6 +206,7 @@ namespace CSVRender
mCurrentObj = result.first; mCurrentObj = result.first;
} }
//#if 0
// print some debug info // print some debug info
std::string referenceId = mPhysics->sceneNodeToRefId(result.first); std::string referenceId = mPhysics->sceneNodeToRefId(result.first);
if(referenceId != "") if(referenceId != "")
@ -215,17 +216,18 @@ namespace CSVRender
std::cout << " hit pos "+ QString::number(result.second.x).toStdString() std::cout << " hit pos "+ QString::number(result.second.x).toStdString()
+ ", " + QString::number(result.second.y).toStdString() + ", " + QString::number(result.second.y).toStdString()
+ ", " + QString::number(result.second.z).toStdString() << std::endl; + ", " + QString::number(result.second.z).toStdString() << std::endl;
//#endif
} }
break; break;
} }
case Mouse_Drag: case Mouse_Drag:
{ {
// final placement // final placement
std::pair<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane); std::pair<bool, Ogre::Vector3> planeResult = mousePosOnPlane(event->pos(), *mPlane);
if(planeResult.first && mGrabbedSceneNode != "") if(planeResult.first && mGrabbedSceneNode != "")
{ {
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis(); Ogre::Vector3 pos = mOrigObjPos + (planeResult.second-mOrigMousePos);
Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos;
// use the saved scene node name since the physics model has not moved yet // use the saved scene node name since the physics model has not moved yet
std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode); std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode);
@ -234,18 +236,19 @@ namespace CSVRender
// move pathgrid point, but don't save yet (need pathgrid // move pathgrid point, but don't save yet (need pathgrid
// table feature & its data structure to be completed) // table feature & its data structure to be completed)
// FIXME: need to signal PathgridPoint object of change // FIXME: need to signal PathgridPoint object of change
// FIXME: shouldn't allow pathgrid points under the cursor //std::pair<std::string, Ogre::Vector3> result =
std::pair<std::string, Ogre::Vector3> result = //anyUnderCursor(event->x(), event->y());
anyUnderCursor(event->x(), event->y()); //std::string refId = mPhysics->sceneNodeToRefId(result.first);
if(result.first != "") //if(result.first != "" && // don't allow pathgrid points under the cursor
//!QString(refId.c_str()).contains(QRegExp("^Pathgrid")))
{ {
// FIXME: rather than just updating at the end, should // FIXME: rather than just updating at the end, should
// consider providing visual feedback of terrain height // consider providing visual feedback of terrain height
// while dragging the pathgrid point (maybe check whether // while dragging the pathgrid point (maybe check whether
// the object is a pathgrid point at the begging and set // the object is a pathgrid point at the begging and set
// a flag?) // a flag?)
placeObject(mGrabbedSceneNode, result.second); placeObject(mGrabbedSceneNode, pos); // result.second
mParent->pathgridMoved(referenceId, result.second); mParent->pathgridMoved(referenceId, pos); // result.second
} }
} }
else else
@ -267,12 +270,11 @@ namespace CSVRender
mMouseState = Mouse_Edit; mMouseState = Mouse_Edit;
// reset states // reset states
mCurrentMousePos = Ogre::Vector3(); // mouse pos to use in wheel event mGrabbedSceneNode = ""; // id of the object
mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space
mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space
mGrabbedSceneNode = ""; // id of the object mOldMousePos = Ogre::Vector3(); // mouse pos to use in wheel event
mOffset = 0.0f; // used for z-axis movement mOldCursorPos = QPoint(0, 0); // to calculate relative movement of mouse
mOldPos = QPoint(0, 0); // to calculate relative movement of mouse
} }
break; break;
} }
@ -284,10 +286,12 @@ namespace CSVRender
if(result.first != "") if(result.first != "")
{ {
// FIXME: terrain editing goes here // FIXME: terrain editing goes here
//#if 0
std::cout << "result default/edit release: " << result.first << std::endl; std::cout << "result default/edit release: " << result.first << std::endl;
std::cout << " hit pos "+ QString::number(result.second.x).toStdString() std::cout << " hit pos "+ QString::number(result.second.x).toStdString()
+ ", " + QString::number(result.second.y).toStdString() + ", " + QString::number(result.second.y).toStdString()
+ ", " + QString::number(result.second.z).toStdString() << std::endl; + ", " + QString::number(result.second.z).toStdString() << std::endl;
//#endif
} }
break; break;
} }
@ -298,9 +302,9 @@ namespace CSVRender
void MouseState::mouseDoubleClickEvent (QMouseEvent *event) void MouseState::mouseDoubleClickEvent (QMouseEvent *event)
{ {
//event->ignore(); event->ignore();
mPhysics->toggleDebugRendering(mSceneManager); //mPhysics->toggleDebugRendering(mSceneManager);
mParent->flagAsModified(); //mParent->flagAsModified();
} }
bool MouseState::wheelEvent (QWheelEvent *event) bool MouseState::wheelEvent (QWheelEvent *event)
@ -313,17 +317,47 @@ namespace CSVRender
/* FALL_THROUGH */ /* FALL_THROUGH */
case Mouse_Drag: case Mouse_Drag:
{ {
// move the object along the z axis during Mouse_Drag or Mouse_Grab // move the object along the axis normal to the plane during Mouse_Drag or Mouse_Grab
if (event->delta()) if (event->delta())
{ {
// seems positive is up and negative is down // The mouse point is where the mouse points the object when dragging starts.
mOffset += (event->delta()/1); // FIXME: arbitrary number, make config option? // The object position is usually a little away from the mount point.
// Get the new world position of mouse on the plane offset from the wheel
std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis(); std::pair<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis();
Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset; Ogre::Vector3 mousePos = mOldMousePos + planeRes.first*(event->delta()/2);
mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos);
mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+mCurrentMousePos-mOrigMousePos); // Move the movement plane to the new mouse position. The plane is created on
// the mouse point (i.e. not the object position)
mPlane->redefine(planeRes.first, mousePos);
// Calculate the new screen position of the cursor
Ogre::Vector3 screenPos =
getCamera()->getProjectionMatrix() * getCamera()->getViewMatrix() * mousePos;
int screenX = (screenPos.x/2+0.5) * getViewport()->getActualWidth();
int screenY = (1-(screenPos.y/2+0.5)) * getViewport()->getActualHeight();
// Move the cursor to the new screen position
QCursor::setPos(mParent->mapToGlobal(QPoint(screenX, screenY)));
// Use the new position to check the world position of the mouse
std::pair<bool, Ogre::Vector3> planeResult =
mousePosOnPlane(QPoint(screenX, screenY), *mPlane);
{
if(planeResult.first)
mousePos = planeResult.second;
}
// Find the final world position of the cursor
Ogre::Vector3 finalPos = mOrigObjPos + (mousePos-mOrigMousePos);
mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(finalPos);
mPhysics->moveSceneNodes(mGrabbedSceneNode, finalPos);
updateSceneWidgets(); updateSceneWidgets();
// remember positions for next time
mOldMousePos = mousePos;
mOldCursorPos = QPoint(screenX, screenY);
} }
break; break;
} }
@ -353,14 +387,13 @@ namespace CSVRender
// reset states // reset states
mMouseState = Mouse_Default; mMouseState = Mouse_Default;
mCurrentMousePos = Ogre::Vector3(); mOldMousePos = Ogre::Vector3();
mOrigMousePos = Ogre::Vector3(); mOrigMousePos = Ogre::Vector3();
mOrigObjPos = Ogre::Vector3(); mOrigObjPos = Ogre::Vector3();
mGrabbedSceneNode = ""; mGrabbedSceneNode = "";
mCurrentObj = ""; mCurrentObj = "";
mOldPos = QPoint(0, 0); mOldCursorPos = QPoint(0, 0);
mMouseEventTimer->invalidate(); mMouseEventTimer->invalidate();
mOffset = 0.0f;
break; break;
} }
@ -420,7 +453,7 @@ namespace CSVRender
return std::make_pair("", Ogre::Vector3()); return std::make_pair("", Ogre::Vector3());
} }
std::pair<bool, Ogre::Vector3> MouseState::mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane) std::pair<bool, Ogre::Vector3> MouseState::mousePosOnPlane(const QPoint &pos, const Ogre::Plane &plane)
{ {
// using a really small value seems to mess up with the projections // using a really small value seems to mess up with the projections
float nearClipDistance = getCamera()->getNearClipDistance(); // save existing float nearClipDistance = getCamera()->getNearClipDistance(); // save existing

View file

@ -46,15 +46,14 @@ namespace CSVRender
CSVWorld::PhysicsSystem *mPhysics; // local copy CSVWorld::PhysicsSystem *mPhysics; // local copy
Ogre::SceneManager *mSceneManager; // local copy Ogre::SceneManager *mSceneManager; // local copy
QPoint mOldPos; QPoint mOldCursorPos;
std::string mCurrentObj; std::string mCurrentObj;
std::string mGrabbedSceneNode; std::string mGrabbedSceneNode;
QElapsedTimer *mMouseEventTimer; QElapsedTimer *mMouseEventTimer;
Ogre::Plane *mPlane; Ogre::Plane *mPlane;
Ogre::Vector3 mOrigObjPos; Ogre::Vector3 mOrigObjPos;
Ogre::Vector3 mOrigMousePos; Ogre::Vector3 mOrigMousePos;
Ogre::Vector3 mCurrentMousePos; Ogre::Vector3 mOldMousePos;
float mOffset;
CSMWorld::IdTable *mIdTableModel; CSMWorld::IdTable *mIdTableModel;
int mColIndexPosX; int mColIndexPosX;
@ -78,7 +77,7 @@ namespace CSVRender
private: private:
std::pair<bool, Ogre::Vector3> mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); std::pair<bool, Ogre::Vector3> mousePosOnPlane(const QPoint &pos, const Ogre::Plane &plane);
std::pair<std::string, Ogre::Vector3> terrainUnderCursor(const int mouseX, const int mouseY); std::pair<std::string, Ogre::Vector3> terrainUnderCursor(const int mouseX, const int mouseY);
std::pair<std::string, Ogre::Vector3> objectUnderCursor(const int mouseX, const int mouseY); std::pair<std::string, Ogre::Vector3> objectUnderCursor(const int mouseX, const int mouseY);
std::pair<Ogre::Vector3, Ogre::Vector3> planeAxis(); std::pair<Ogre::Vector3, Ogre::Vector3> planeAxis();