/*////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2000 Microsoft Corporation. All Rights Reserved. // //////////////////////////////////////////////////////////////////////////////*/ /* * Simple arcball rotation control using quaternions * Peter-Pike Sloan */ // Rewritten to use D3DX types. --- Jed Lengyel #include "GTArcBall.h" // constructors - default makes most sense, SetWindow is what's important. GTArcBall::GTArcBall() { Reset(); } GTArcBall::GTArcBall(int x, int y) : m_pCenter((float)x,(float)y,0.0f) { Reset(); } GTArcBall::GTArcBall(D3DXVECTOR3 center) { m_pCenter = center; Reset(); } void GTArcBall::Reset() { D3DXQuaternionIdentity(&m_qNow); m_bDrag = false; } void GTArcBall::SetWindow(int w, int h, float r) { m_iWidth = w; m_iHeight = h; m_fRadius = r; // set win info m_pCenter = D3DXVECTOR3(w/2.f,h/2.f,0.0f); // set center } void GTArcBall::BeginDrag(int x, int y) { m_qDown = m_qNow; m_bDrag = true; m_vDown = ScreenToVector(x,y); } void GTArcBall::EndDrag() { m_bDrag = false; } void GTArcBall::Mouse(int x, int y) { if (m_bDrag) { // ignore it if you aren't dragging m_vCur = ScreenToVector(x,y); Update(); // always build m_qNow } } void GTArcBall::GetMatrix(D3DXMATRIX *pmat) { D3DXMatrixRotationQuaternion(pmat, &m_qNow); } D3DXVECTOR3 GTArcBall::ScreenToVector(int ix, int iy) { float x, y, z; x = (ix - m_pCenter.x)/(m_iWidth*m_fRadius*0.5f); // scales to screen #if 1 y = (m_pCenter.y - iy)/(m_iHeight*m_fRadius*0.5f); // invert Y coordinate #else y = (iy - m_pCenter.y)/(m_iHeight*m_fRadius*0.5f); #endif float mag = x*x + y*y; if (mag > 1.f) { float scale = 1.f/sqrtf(mag); x *= scale; y *= scale; z = 0.0; } else { z = sqrtf(1.f-mag); } return D3DXVECTOR3(-x, -y, z); //-x and -y : hack so that the rotation is //in the way we wait } void GTArcBall::Update() { if (m_bDrag) { // recompute m_qNow D3DXQUATERNION qAxisToAxis; D3DXQuaternionAxisToAxis(&qAxisToAxis, &m_vDown, &m_vCur); m_qNow = m_qDown; m_qNow *= qAxisToAxis; } }