在项目中,为了是设计更人性化,经常会要用鼠标去拖动物体,于是我就花时间写了个demo。
之前我没有知道有MOUSEMOVE这个消息,于是就自己去想用LBUTTONDOWN和LBUTTONUP去实现MOUSEMOVE这个功能,最后悲剧了。
开始我的想法是这样的,用POINT记录前后两次鼠标的位置,然后通过射线碰撞求出两个交点,进而求出平移矩阵。
定义结构体记录鼠标点击的信息。
typedef struct CursorInfo
{
Point oldpoint;
Point newpoint;
bool oldclick;
}CursorInfo;
响应鼠标点击事件:
1、 LBUTTONDOWN。如果oldclick为false,则令oldclick为true,并记录鼠标点击位置oldpoint;如果oldclick为true,则记录当前鼠标点击位置newpoint,并将oldclick置为false。通过oldpoint和newpoint计算平移矩阵与物体原来的矩阵相乘即可。只有当oldpoint与物体相交时才计算平移矩阵并且进行矩阵的相关运算。
2、 LBUTTONDOWNUP。oldclick置为false。
后来我发现,如果你一直按着鼠标左键,是只响应一次LBUTTONDOWN消息的,这样的话就无法执行oldclick为true的情况,也几是说无法移动物体。
在我查看LBUTTONDOWN的宏定义的时候发现了MOUSEMOVE这个消息,然后就想出了响应鼠标移动的消息。有了MOUSEMOVE,整个算法就很简单了,只要在LBUTTONDOWN和LBUTTONUP一对消息之间对MOUSEMOVE消息进行处理就行了,也就是不停的获取鼠标的位置,利用新旧两个鼠标的位置就可以求出平移矩阵,主要代码如下
void MoveMesh(UINT uMsg, ID3DXMesh *pMesh, D3DXMATRIX &World, float Plane)
{
float u, v, t;
::GetCursorPos(&m_NewPoint);
::ScreenToClient(DXUTGetHWND(), &m_NewPoint);
switch(uMsg)
{
case WM_LBUTTONDOWN:
{
if( !m_LClick )
{
m_LClick = true;
m_Pick = m_pPickManager->IsPick(m_NewPoint.x, m_NewPoint.y, pMesh, World, t, u, v );
m_OldPoint = m_NewPoint;
}
}
break;
case WM_LBUTTONUP:
{
m_LClick = false;
m_Pick = false;
}
break;
case WM_MOUSEMOVE:
if( m_Pick )
{
::GetCursorPos(&m_NewPoint);
::ScreenToClient(DXUTGetHWND(), &m_NewPoint);
if(m_pPickManager->IsPick(m_OldPoint.x, m_OldPoint.y, pMesh, World, t, u, v ))
{
D3DXMATRIX world;
CaculateMatrix( world, m_OldPoint, m_NewPoint, Plane );
World *= world;
}
m_OldPoint = m_NewPoint;
}
break;
}
}