В приложении MorphPlay есть четыре функции для реализации возможности вращения сетки: OnLButtonDown(), OnLButtonUp(), UpdateDrag() и OnIdle(). Давайте сначала взглянем на код функции OnLButtonDown():
void MorphPlayWin::OnLButtonDown(UINT nFlags, CPoint point) { if (!drag) { drag = TRUE; last_x = GetMouseX(); last_y = GetMouseY(); ShowCursor(FALSE); SetCapture(); } MorphWin::OnLButtonDown(nFlags, point); }Функция начинает новую операцию перетаскивания, если только она уже не начата. Переменная drag используется для контроля текущего состояния операции перетаскивания. В начале операции перетаскивания сохраняется текущая позиция указателя мыши, сам указатель убирается с экрана, и мышь захватывается приложением с помощью функции MFC SetCapture(). После вызова функции SetCapture() все поступающие от мыши сообщения будут направляться приложению, которое захватило мышь, независимо от того, в каком месте экрана находится указатель мыши.
Функция OnLButtonUp() выглядит следующим образом:
void MorphPlayWin::OnLButtonUp(UINT nFlags, CPoint point) { if (drag) { end_drag = TRUE; ReleaseCapture(); ShowCursor(TRUE); } MorphWin::OnLButtonUp(nFlags, point); }Сначала функция OnLButtonUp() проверяет, существует ли начатая операция перетаскивания. Если да, то переменной end_drag присваивается значение TRUE, что указывает на необходимость прекращения операции перетаскивания. Затем приложение освобождает мышь с помощью функции ReleaseCapture() и разрешает отображение указателя мыши.
Функция обратного вызова UpdateDrag() отвечает за вращение трансформируемой сетки при ее перетаскивании. Вот как выглядит код функции:
void MorphPlayWin::UpdateDrag(LPDIRECT3DRMFRAME frame, void*, D3DVALUE) { if (drag) { double delta_x, delta_y; int x = GetMouseX(); int y = GetMouseY(); delta_x = x - last_x; delta_y = y - last_y; last_x = x; last_y = y; double delta_r = sqrt(delta_x * delta_x + delta_y * delta_y); double radius = 50; double denom; denom = sqrt(radius * radius + delta_r * delta_r); if (!(delta_r == 0 || denom == 0)) frame->SetRotation(0, D3DDivide(D3DVAL((float)-delta_y), D3DVAL((float)delta_r)), D3DDivide(D3DVAL((float)-delta_x), D3DVAL((float)delta_r)), D3DVAL(0.0), D3DDivide(D3DVAL((float)delta_r), D3DVAL((float)denom))); } if (end_drag) { drag = FALSE; end_drag = FALSE; } }Функция UpdateDrag() преобразует данные о перемещении мыши (сохраненные в переменных x, y, last_x и last_y) для вычисления вектора вращения сетки. Новые атрибуты вращения назначаются с помощью функции SetRotation() интерфейса Direct3DRMFrame.
В конце приведем код функции OnIdle(), которая используется для предотвращения беспорядочного вращения сетки в момент операции перетаскивания.
void MorphPlayWin::OnIdle(LONG) { if (drag && frame) frame->SetRotation(0, D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0), D3DVAL(0.0)); }