VectorCtl.cpp
Upload User: bjzhiyi
Upload Date: 2007-01-01
Package Size: 40k
Code Size: 11k
Category:

OpenGL program

Development Platform:

Visual C++

  1. #include "stdafx.h"
  2. #include "VectorCtl.h"
  3. #include <math.h>
  4. CVectorCtl::CVectorCtl () :
  5.     m_bBmpCreated (FALSE), 
  6.     m_bImageChange (TRUE),
  7.     m_bBackgroundBitmapUsed (FALSE),
  8.     m_clrDiffuse (DEFAULT_DIFFUSE),
  9.     m_clrAmbient (DEFAULT_AMBIENT),
  10.     m_clrLight (DEFAULT_LIGHT),
  11.     m_clrBackgroundStart (DEFAULT_START_BACKGROUND_COLOR),
  12.     m_clrBackgroundEnd (DEFAULT_END_BACKGROUND_COLOR),
  13.     m_dSpecularExponent (DEFAULT_SPEC_EXP),
  14.     m_bHasFocus (FALSE), 
  15.     m_bSelected (FALSE),
  16.     m_bFrontVector (FALSE),
  17.     m_iLastMouseY (VAL_NOT_IN_USE), 
  18.     m_iLastMouseX (VAL_NOT_IN_USE),
  19.     m_dSensitivity (20.0),
  20.     m_procVectorChanging (NULL),
  21.     m_procVectorChanged (NULL)
  22. {
  23.     double DefaultVec[3] = DEFAULT_VEC;
  24.     for (int i=0; i<3; i++) {
  25.         m_dVec[i] = DefaultVec[i];
  26.         pCtl[i] = NULL;
  27.     }
  28. }
  29. CVectorCtl::~CVectorCtl () 
  30. {
  31.     if (m_bBmpCreated) 
  32.         m_dcMem.SelectObject (m_pOldBitmap);
  33.     ClearBackgroundBitmap ();
  34. }
  35. // Owner-drawn control service function:
  36. void CVectorCtl::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
  37. {
  38.     CDC *pDC = CDC::FromHandle (lpDrawItemStruct->hDC); // Get CDC to draw
  39.     if (!m_bSelected && lpDrawItemStruct->itemState & ODS_SELECTED) {
  40.             // Just got re-selected (user starts a new mouse dragging session)
  41.         m_iLastMouseX = VAL_NOT_IN_USE;
  42.         m_iLastMouseY = VAL_NOT_IN_USE;                
  43.     } else if (m_bSelected && // Last state was selected
  44.                !(lpDrawItemStruct->itemState & ODS_SELECTED) &&     // New state is NOT selected   
  45.                (lpDrawItemStruct->itemState & ODS_FOCUS) &&         // New state is still in focus
  46.                m_procVectorChanged)     // User asked for a callback
  47.         // User has left the track-ball and asked for a callback.
  48.         m_procVectorChanged (m_dVec[0], m_dVec[1], m_dVec[2]);  // Call it!
  49.           
  50.     m_bHasFocus = lpDrawItemStruct->itemState & ODS_FOCUS;      // Update focus status
  51.     m_bSelected = lpDrawItemStruct->itemState & ODS_SELECTED;   // Update selection status
  52.     if (!m_bBmpCreated)  // 1st time
  53.         InitBitmap (lpDrawItemStruct, pDC);
  54.     if (m_bImageChange) {   // Image has changes - recalc it!
  55.         if (m_procVectorChanging)   // User has specified a callback
  56.             m_procVectorChanging (m_dVec[0], m_dVec[1], m_dVec[2]); // Call it!
  57.         BuildImage (lpDrawItemStruct);
  58.         m_bImageChange = FALSE;
  59.     }
  60.     pDC->BitBlt (0,0,m_iWidth, m_iHeight, &m_dcMem, 0, 0, SRCCOPY); // Update screen
  61. }
  62. // Mouse was dragged 
  63. void CVectorCtl::OnMouseDrag (int ixMove, int iyMove)
  64. {
  65.     RotateByXandY (double(-iyMove) / m_dSensitivity,
  66.                    double(ixMove) / m_dSensitivity);
  67. }
  68. // Recalc ball image
  69. void CVectorCtl::BuildImage (LPDRAWITEMSTRUCT lpDrawItemStruct)
  70. {
  71.     int xf, yf;
  72.     for (int x=0; x<m_iWidth; x++)  // Scan all columns
  73.         for (int y=0; y<m_iHeight; y++) {   // Scan all rows
  74.             xf = x-m_iXCenter;  // Find distance from center
  75.             yf = y-m_iYCenter;
  76.             if (xf*xf + yf*yf <= m_iSqrRadius) {    // Point on ball surface
  77.                 double vx = double(xf) / double(m_iRadius),
  78.                        vy = double(yf) / double(m_iRadius),
  79.                        vz = sqrt (1.0 - vx*vx - vy*vy);     // Find ball's normal
  80.                 m_dcMem.SetPixelV (x,y, CalcLight (vx,vy,vz));
  81.             } 
  82.         }
  83. }
  84. // Normalize a vector to unit size
  85. BOOL CVectorCtl::Normalize ()
  86. {
  87.     double Norm = m_dVec[0] * m_dVec[0] + m_dVec[1] * m_dVec[1] + m_dVec[2] * m_dVec[2];
  88.     if (Norm > EPS) {
  89.         Norm = sqrt (Norm);
  90.         m_dVec[0] /= Norm;
  91.         m_dVec[1] /= Norm;
  92.         m_dVec[2] /= Norm;
  93.         return TRUE;
  94.     } else {    // Reset to defualt vector
  95.         double DefaultVec[3] = DEFAULT_VEC;
  96.         for (int i=0; i<3; i++) 
  97.             m_dVec[i] = DefaultVec[i];
  98.         return FALSE;
  99.     }
  100. }
  101. // Calculate lightning effect for specific pixel on ball's surface
  102. COLORREF CVectorCtl::CalcLight (double dx, double dy, double dz)
  103. {
  104.     double NL = dx * m_dVec[0] + dy * m_dVec[1] + dz * m_dVec[2], 
  105.            RV = 2.0 * NL,
  106.            rx = m_dVec[0] - (dx * RV),
  107.            ry = m_dVec[1] - (dy * RV),
  108.            rz = m_dVec[2] - (dz * RV);
  109.     if (NL < 0.0)   // Diffuse coefficient
  110.         NL = 0.0;
  111.     RV = max (0.0, -rz);
  112.     RV = double(pow (RV, m_dSpecularExponent));
  113.     int  r = int (  double(GetRValue(m_clrDiffuse)) * NL +  // Diffuse
  114.                     double(GetRValue(m_clrLight)) * RV +    // Specular
  115.                     double(GetRValue(m_clrAmbient))),       // Ambient
  116.          g = int (  double(GetGValue(m_clrDiffuse)) * NL +  // Diffuse
  117.                     double(GetGValue(m_clrLight)) * RV +    // Specular
  118.                     double(GetGValue(m_clrAmbient))),       // Ambient    
  119.          b = int (  double(GetBValue(m_clrDiffuse)) * NL +  // Diffuse
  120.                     double(GetBValue(m_clrLight)) * RV +    // Specular
  121.                     double(GetBValue(m_clrAmbient)));       // Ambient
  122.     r = min (255, r);   // Cutoff highlight
  123.     g = min (255, g);
  124.     b = min (255, b);
  125.     return RGB(BYTE(r),BYTE(g),BYTE(b));
  126. }
  127. // Start memory buffer bitmap and measure it
  128. void CVectorCtl::InitBitmap (LPDRAWITEMSTRUCT lpDrawItemStruct, CDC *pDC)
  129. {
  130.     m_iWidth = lpDrawItemStruct->rcItem.right - lpDrawItemStruct->rcItem.left;
  131.     m_iHeight = lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top;
  132.     m_bmpBuffer.CreateCompatibleBitmap (pDC, m_iWidth, m_iHeight);
  133.     m_bBmpCreated = TRUE;
  134.     m_dcMem.CreateCompatibleDC (pDC);
  135.     m_pOldBitmap = m_dcMem.SelectObject (&m_bmpBuffer);
  136.     SetRadius (max (min (m_iWidth, m_iHeight) - 2, 0) / 2);
  137.     SetCenter (m_iWidth / 2, m_iHeight / 2);
  138.     CreateBackground ();
  139. }
  140. // Set new specular intensity
  141. BOOL CVectorCtl::SetSpecularExponent (double dExp)
  142. {
  143.     if (dExp < 1.0 || dExp > 200.0)
  144.         return FALSE;
  145.     m_dSpecularExponent = dExp;
  146.     Redraw ();
  147.     return TRUE;
  148. }
  149. // Rotate our vector around the X and Y axis
  150. void CVectorCtl::RotateByXandY (double XRot, double YRot)
  151. {   // Angles are in radians
  152.     if (XRot == 0.0 && YRot == 0.0)
  153.         return;
  154.     double cx = cos(XRot),
  155.            sx = sin(XRot),
  156.            cy = cos(YRot),
  157.            sy = sin(YRot),
  158.            dx = m_dVec[0] * cy + m_dVec[1] * sx * sy + m_dVec[2] * cx * sy,
  159.            dy = m_dVec[1] * cx - m_dVec[2] * sx,
  160.            dz = -m_dVec[0] * sy + m_dVec[1] * sx * cy + m_dVec[2] * cx * cy;
  161.     if (!m_bFrontVector || dz >= 0.0) { // Vector is bounds free
  162.         m_dVec[0] = dx;
  163.         m_dVec[1] = dy;
  164.         m_dVec[2] = dz;
  165.     } else {    // Otherwise, do not allow Z to be negative (light shines from behind)
  166.         m_dVec[2] = 0.0;
  167.         m_dVec[0] = dx;
  168.         m_dVec[1] = dy;
  169.         Normalize ();
  170.     }
  171.     Redraw ();
  172. }
  173.  
  174. void CVectorCtl::UpdateAxisControls ()
  175. {
  176.     CString cs;
  177.     for (int i=0; i<3; i++) 
  178.         if (pCtl[i]) {
  179.             cs.Format ("%+1.5f",m_dVec[i]);
  180.             pCtl[i]->SetWindowText (cs);
  181.         }
  182. }            
  183. void CVectorCtl::SetAxisControl (int nXCtl, int nYCtl, int nZCtl)
  184. {
  185.     pCtl[0] = GetParent()->GetDlgItem(nXCtl);
  186.     pCtl[1] = GetParent()->GetDlgItem(nYCtl);
  187.     pCtl[2] = GetParent()->GetDlgItem(nZCtl);
  188. }
  189. void CVectorCtl::SetRadius (UINT uRadius)
  190. {
  191.     m_iRadius = uRadius;
  192.     m_iSqrRadius = m_iRadius * m_iRadius;
  193.     CreateBackground ();
  194.     Redraw (TRUE);
  195. }
  196. void CVectorCtl::SetCenter (UINT uHorizPos, UINT uVertPos)
  197. {
  198.     m_iXCenter = uHorizPos;
  199.     m_iYCenter = uVertPos;
  200.     CreateBackground ();
  201.     Redraw (TRUE);
  202. }
  203. void CVectorCtl::SetAxis (double d, int nAxis)
  204. {
  205.     if (fabs(d)>=1.0) {
  206.         m_dVec[nAxis]=d > 1.0 ? 1.0 : -1.0;
  207.         m_dVec[(nAxis+1) %3]=m_dVec[(nAxis+2) %3]=0.0;
  208.         Redraw ();
  209.         return;
  210.     } 
  211.     m_dVec[nAxis] = d;
  212.     Normalize ();
  213.     Redraw ();
  214. }
  215. void CVectorCtl::SetVector (double dx, double dy, double dz)
  216. {
  217.     m_dVec[0] = dx;
  218.     m_dVec[1] = dy;
  219.     m_dVec[2] = dz;
  220.     Normalize ();
  221.     Redraw ();
  222. }
  223. void CVectorCtl::SetBackgroundColor (COLORREF clrStart, COLORREF clrEnd)
  224. {
  225.     ClearBackgroundBitmap ();
  226.     m_clrBackgroundStart = clrStart;
  227.     m_clrBackgroundEnd = clrEnd;
  228.     CreateBackground ();
  229. }
  230. BOOL CVectorCtl::SetBackgroundImage (UINT uBackgroundBitmapID)
  231. {
  232.     if (m_bBackgroundBitmapUsed) {
  233.         ClearBackgroundBitmap ();
  234.         CreateBackground ();
  235.     }
  236.     if (!m_bmpBack.LoadBitmap (uBackgroundBitmapID))
  237.         return FALSE;
  238.     m_bBackgroundBitmapUsed = TRUE;
  239.     CreateBackground ();
  240.     return TRUE;
  241. }
  242. void CVectorCtl::CreateBackground ()
  243. {
  244.     if (!m_bBmpCreated)
  245.         return; //  No image yet
  246.     if (!m_bBackgroundBitmapUsed) { // No background used - fill with gradient color
  247.         double r = GetRValue (m_clrBackgroundStart),
  248.                g = GetGValue (m_clrBackgroundStart),
  249.                b = GetBValue (m_clrBackgroundStart), 
  250.                rd = double (GetRValue (m_clrBackgroundEnd) - r) / double (m_iHeight),
  251.                gd = double (GetGValue (m_clrBackgroundEnd) - g) / double (m_iHeight), 
  252.                bd = double (GetBValue (m_clrBackgroundEnd) - b) / double (m_iHeight);
  253.         for (int j=0; j<m_iHeight; j++) {
  254.             for (int i=0; i<m_iWidth; i++)
  255.                 m_dcMem.SetPixelV (i,j, RGB (BYTE(r),BYTE(g),BYTE(b)));
  256.             r+=rd; g+=gd; b+=bd;
  257.         }
  258.         Redraw (TRUE);
  259.         return;
  260.     }
  261.     // Bitmap used : tile it in back
  262.     CDC DCtmp;
  263.     BITMAP tmpBitmap;
  264.     m_bmpBack.GetBitmap (&tmpBitmap);
  265.     int iTmpWidth = tmpBitmap.bmWidth,
  266.         iTmpHeight = tmpBitmap.bmHeight;
  267.     DCtmp.CreateCompatibleDC (&m_dcMem);
  268.     m_pOldBitmap = DCtmp.SelectObject (&m_bmpBack);
  269.     
  270.     for (int i=0; i<m_iWidth; i++)
  271.         for (int j=0; j<m_iHeight; j++)
  272.             m_dcMem.SetPixelV (i,j, DCtmp.GetPixel (i % iTmpWidth, j % iTmpHeight));
  273.     DCtmp.SelectObject (m_pOldBitmap);
  274.     Redraw (TRUE);
  275. }    
  276.     
  277. void CVectorCtl::ClearBackgroundBitmap ()
  278. {
  279.     if (!m_bBackgroundBitmapUsed)
  280.         return;
  281.     m_bmpBack.DeleteObject ();
  282.     m_bBackgroundBitmapUsed = FALSE;
  283. }
  284. BOOL CVectorCtl::SetSensitivity (UINT uSens)
  285. {
  286.     if (uSens == 0)
  287.         return FALSE;
  288.     m_dSensitivity = double(uSens);
  289.     return TRUE;
  290. }
  291. void CVectorCtl::Redraw (BOOL bErase)
  292. {
  293.     m_bImageChange = TRUE;
  294.     UpdateAxisControls();
  295.     Invalidate (bErase);
  296. }
  297. LRESULT CVectorCtl::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
  298. {
  299.     if (message == WM_MOUSEMOVE && (wParam & MK_LBUTTON)) {
  300.         // Mouse has moved and left button is down
  301.         WORD wCurX = LOWORD(lParam);
  302.         WORD wCurY = HIWORD(lParam);
  303.         int iCurX = wCurX > 3000 ? int(int(wCurX) - 0xffff) : int(wCurX);
  304.         int iCurY = wCurY > 3000 ? int(int(wCurY) - 0xffff) : int(wCurY);
  305.         
  306.         OnMouseDrag (m_iLastMouseX != VAL_NOT_IN_USE ? iCurX - m_iLastMouseX : 0, 
  307.                      m_iLastMouseY != VAL_NOT_IN_USE ? iCurY - m_iLastMouseY : 0);
  308.         m_iLastMouseX = iCurX;
  309.         m_iLastMouseY = iCurY;
  310.     }   
  311.     return CButton::WindowProc (message, wParam, lParam);
  312. }