/* ** Command & Conquer Renegade(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ // VisErrorReportDialog.cpp : implementation file // #include "StdAfx.H" #include "LevelEdit.H" #include "VisErrorReportDialog.H" #include "Utils.H" #include "VisLog.H" #include "SceneEditor.H" #include "CameraMgr.H" #include "phys.h" #include "rendobj.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // // Constants // ///////////////////////////////////////////////////////////////////////////// static const int AXIS_BMP_WIDTH = 65; static const int AXIS_BMP_HEIGHT = 65; ///////////////////////////////////////////////////////////////////////////// // // Local Inlines // ///////////////////////////////////////////////////////////////////////////// static inline HBITMAP Load_Bitmap (UINT res_id) { return (HBITMAP)::LoadImage (::AfxGetResourceHandle (), MAKEINTRESOURCE (res_id), IMAGE_BITMAP, 0, 0, LR_LOADTRANSPARENT); } ///////////////////////////////////////////////////////////////////////////// // // VisErrorReportDialogClass // ///////////////////////////////////////////////////////////////////////////// VisErrorReportDialogClass::VisErrorReportDialogClass (CWnd *pParent) : m_CurrentPoint (0), m_GraphArea (0, 0, 0, 0), m_AxisArea (0, 0, 0, 0), m_CurrentMinPoint (0), m_CurrentMaxPoint (0), m_TotalPoints (0), m_bTrackingSel (false), m_TrackPixel (0), m_SelStartIndex (0), m_SelEndIndex (0), m_AxisBMP (NULL), m_AxisSelBMP (NULL), m_AxisSel (0), CDialog(VisErrorReportDialogClass::IDD, pParent) { //{{AFX_DATA_INIT(VisErrorReportDialogClass) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT m_PrevButton.normal = Load_Bitmap (IDB_LT_ARROW); m_PrevButton.disabled = Load_Bitmap (IDB_LT_ARROW_D); m_NextButton.normal = Load_Bitmap (IDB_RT_ARROW); m_NextButton.disabled = Load_Bitmap (IDB_RT_ARROW_D); m_AxisBMP = Load_Bitmap (IDB_AXIS_BMP); m_AxisSelBMP = Load_Bitmap (IDB_AXIS_SEL_BMP); m_AxisSelAreas[VIS_FORWARD].left = 1; m_AxisSelAreas[VIS_FORWARD].top = 38; m_AxisSelAreas[VIS_FORWARD].right = m_AxisSelAreas[VIS_FORWARD].left + 20; m_AxisSelAreas[VIS_FORWARD].bottom = m_AxisSelAreas[VIS_FORWARD].top + 16; m_AxisSelAreas[VIS_LEFT].left = 1; m_AxisSelAreas[VIS_LEFT].top = 12; m_AxisSelAreas[VIS_LEFT].right = m_AxisSelAreas[VIS_LEFT].left + 20; m_AxisSelAreas[VIS_LEFT].bottom = m_AxisSelAreas[VIS_LEFT].top + 16; m_AxisSelAreas[VIS_BACKWARDS].left = 42; m_AxisSelAreas[VIS_BACKWARDS].top = 13; m_AxisSelAreas[VIS_BACKWARDS].right = m_AxisSelAreas[VIS_BACKWARDS].left + 20; m_AxisSelAreas[VIS_BACKWARDS].bottom = m_AxisSelAreas[VIS_BACKWARDS].top + 16; m_AxisSelAreas[VIS_RIGHT].left = 42; m_AxisSelAreas[VIS_RIGHT].top = 39; m_AxisSelAreas[VIS_RIGHT].right = m_AxisSelAreas[VIS_RIGHT].left + 20; m_AxisSelAreas[VIS_RIGHT].bottom = m_AxisSelAreas[VIS_RIGHT].top + 16; m_AxisSelAreas[VIS_UP].left = 21; m_AxisSelAreas[VIS_UP].top = 1; m_AxisSelAreas[VIS_UP].right = m_AxisSelAreas[VIS_UP].left + 20; m_AxisSelAreas[VIS_UP].bottom = m_AxisSelAreas[VIS_UP].top + 16; m_AxisSelAreas[VIS_DOWN].left = 22; m_AxisSelAreas[VIS_DOWN].top = 47; m_AxisSelAreas[VIS_DOWN].right = m_AxisSelAreas[VIS_DOWN].left + 20; m_AxisSelAreas[VIS_DOWN].bottom = m_AxisSelAreas[VIS_DOWN].top + 16; return ; } ///////////////////////////////////////////////////////////////////////////// // // ~VisErrorReportDialogClass // ///////////////////////////////////////////////////////////////////////////// VisErrorReportDialogClass::~VisErrorReportDialogClass (void) { // // Free the BMPs // if (m_PrevButton.normal) ::DeleteObject (m_PrevButton.normal); if (m_PrevButton.disabled) ::DeleteObject (m_PrevButton.disabled); if (m_NextButton.normal) ::DeleteObject (m_NextButton.normal); if (m_NextButton.disabled) ::DeleteObject (m_NextButton.disabled); Free_Point_List (); return ; } ///////////////////////////////////////////////////////////////////////////// // // DoDataExchange // ///////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::DoDataExchange (CDataExchange *pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(VisErrorReportDialogClass) DDX_Control(pDX, IDC_ZOOM_SLIDER, m_ZoomSlider); //}}AFX_DATA_MAP return ; } BEGIN_MESSAGE_MAP(VisErrorReportDialogClass, CDialog) //{{AFX_MSG_MAP(VisErrorReportDialogClass) ON_WM_PAINT() ON_WM_VSCROLL() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_BN_CLICKED(IDC_PREV_ERROR, OnPrevError) ON_BN_CLICKED(IDC_NEXT_ERROR, OnNextError) ON_WM_DRAWITEM() ON_WM_NCHITTEST() ON_WM_SETCURSOR() ON_WM_DESTROY() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // // OnInitDialog // ///////////////////////////////////////////////////////////////////////////// BOOL VisErrorReportDialogClass::OnInitDialog (void) { CDialog::OnInitDialog (); // // Register this window for timer-based screen refreshing // ::SetProp (m_hWnd, "ALLOW_UPDATE", (HANDLE)1); // // Set the dimensions of the graph area // ::GetWindowRect (::GetDlgItem (m_hWnd, IDC_HISTOGRAM), &m_GraphArea); ScreenToClient (&m_GraphArea); m_GraphArea.left ++; m_GraphArea.right --; m_GraphArea.top ++; m_GraphArea.bottom --; m_Graph.Set_Dimensions (m_GraphArea.Width (), m_GraphArea.Height ()); // // Set the dimensions of the 'axis' area. // CRect rect; ::GetWindowRect (::GetDlgItem (m_hWnd, IDC_AXIS_AREA), &rect); ScreenToClient (&rect); rect.left ++; rect.right --; rect.top ++; rect.bottom --; m_AxisArea.left = rect.left + (rect.Width () >> 1) - (AXIS_BMP_WIDTH >> 1); m_AxisArea.top = rect.top + (rect.Height () >> 1) - (AXIS_BMP_HEIGHT >> 1); m_AxisArea.right = m_AxisArea.left + AXIS_BMP_WIDTH; m_AxisArea.bottom = m_AxisArea.top + AXIS_BMP_HEIGHT; // Update the dialog with data from the scene Re_Sync_Data (); return TRUE; } ///////////////////////////////////////////////////////////////////////////// // // Re_Sync_Data // ///////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::Re_Sync_Data (void) { // // Get the error list from the scene // VisLogClass &vis_log = ::Get_Scene_Editor ()->Get_Vis_Log (); VIS_SAMPLE_LIST &error_list = vis_log.Peek_Error_List (); m_TotalPoints = error_list.Count (); // // Setup the 'zoom' slider // m_ZoomSlider.SetRange (2, m_TotalPoints >> 1); m_ZoomSlider.SetPos (m_TotalPoints >> 2); // Reset the range of values in the y-axis int max = (m_TotalPoints >> 1) - (m_ZoomSlider.GetPos () - 2); m_Graph.Set_Y_Axis_Range (0, max); // // Add the vis error points to the graph // Free_Point_List (); int bad_points = 0; for (int index = 0; index < error_list.Count (); index ++) { VisSampleClass *sample = error_list[index]; Add_Point (*sample); // // Determining which direction resulted in the largest backface fraction // float fraction = sample->Get_Biggest_Fraction (); m_Graph.Add_Data_Point (fraction); // // Determine if this point was bad or not // int dir_index = sample->Get_Biggest_Fraction_Index (); if (sample->Sample_Status ((VisDirType)dir_index) != VIS_STATUS_OK) { bad_points ++; } } // // Set the dialog text fields // int points = ::Get_Scene_Editor ()->Get_Total_Vis_Points (); SetDlgItemInt (IDC_VIS_POINTS, points); SetDlgItemInt (IDC_BAD_POINTS, bad_points); SetDlgItemInt (IDC_MAX_POINTS, max); int bad_percent = (points > 0) ? ((bad_points * 100) / points) : 0; CString message; message.Format ("%d %%", bad_percent); SetDlgItemText (IDC_PERCENT_BAD, message); m_CurrentPoint = 0; m_CurrentMinPoint = 0; m_CurrentMaxPoint = 0; On_Graph_Sel_Changed (); return ; } ///////////////////////////////////////////////////////////////////////////// // // Refresh_View // ///////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::Refresh_View (void) { if (m_hWnd != NULL) { InvalidateRect (&m_GraphArea, FALSE); UpdateWindow (); } return ; } ///////////////////////////////////////////////////////////////////////////// // // OnPaint // ///////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::OnPaint (void) { CPaintDC dc(this); m_Graph.Render (dc, m_GraphArea.left, m_GraphArea.top); Paint_Axis_Area (dc); return ; } ///////////////////////////////////////////////////////////////////////////// // // OnVScroll // ///////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::OnVScroll ( UINT nSBCode, UINT nPos, CScrollBar *pScrollBar ) { // Reset the range of values in the y-axis int max = m_TotalPoints - (m_ZoomSlider.GetPos () - 2); m_Graph.Set_Y_Axis_Range (0, max); SetDlgItemInt (IDC_MAX_POINTS, max); // // Repaint the graph // Refresh_View (); CDialog::OnVScroll (nSBCode, nPos, pScrollBar); return ; } ///////////////////////////////////////////////////////////////////////////// // // OnLButtonDown // ///////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::OnLButtonDown (UINT nFlags, CPoint point) { if (m_GraphArea.PtInRect (point)) { m_TrackPixel = point.x - m_GraphArea.left; m_Graph.Set_Selection (m_TrackPixel, m_TrackPixel); m_bTrackingSel = true; SetCapture (); Refresh_View (); On_Graph_Sel_Changed (); } else if (m_AxisArea.PtInRect (point)) { Update_Axis_Area (true); } CDialog::OnLButtonDown (nFlags, point); return ; } ///////////////////////////////////////////////////////////////////////////// // // OnLButtonUp // ///////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::OnLButtonUp (UINT nFlags, CPoint point) { if (m_bTrackingSel) { m_bTrackingSel = false; ReleaseCapture (); } CDialog::OnLButtonUp (nFlags, point); return ; } ///////////////////////////////////////////////////////////////////////////// // // OnMouseMove // ///////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::OnMouseMove (UINT nFlags, CPoint point) { if (m_bTrackingSel) { int new_pixel = point.x - m_GraphArea.left; new_pixel = max (new_pixel, 0); new_pixel = min (new_pixel, m_GraphArea.right-1); m_Graph.Set_Selection (m_TrackPixel, new_pixel); Refresh_View (); On_Graph_Sel_Changed (); } CDialog::OnMouseMove (nFlags, point); return ; } ///////////////////////////////////////////////////////////////////////////// // // Display_Point // ///////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::Display_Point (const Matrix3D &transform, bool fly_to) { if (fly_to) { ::Get_Camera_Mgr ()->Fly_To_Transform (transform); } else { ::Get_Camera_Mgr ()->Set_Transform (transform); } ::Refresh_Main_View (); return ; } ////////////////////////////////////////////////////////////////////////////////// // // Free_Point_List // ////////////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::Free_Point_List (void) { // // Delete all the vis samples // for (int index = 0; index < m_PointList.Count (); index ++) { VisSampleClass *vis_sample = m_PointList[index]; SAFE_DELETE (vis_sample); } m_PointList.Delete_All (); return ; } ////////////////////////////////////////////////////////////////////////////////// // // Add_Point // ////////////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::Add_Point (const VisSampleClass &point) { int start = 0; int end = m_PointList.Count (); end = max (end, 0); float fraction = point.Get_Biggest_Fraction (); int index = end; while (end > start) { index = start + ((end - start) >> 1); float curr_fraction = m_PointList[index]->Get_Biggest_Fraction (); if (fraction > curr_fraction) { if (start == index) { index ++; break; } start = index; } else if (fraction < curr_fraction) { if (end == index) { index --; break; } end = index; } else { break; } } ASSERT (index >=0 ); // // Simple binary search to find the right place // to insert the new data point // /*while (end > start) { int index = start + ((end - start) >> 1); float curr_fraction = m_PointList[index]->BackfaceFraction; if ((index == start) || (fraction == curr_fraction)) { break; } else if (fraction > curr_fraction) { start = index; } else if (fraction < curr_fraction) { end = index; } }*/ // // Insert the new point into the list // m_PointList.Insert (index, new VisSampleClass (point)); return ; } ///////////////////////////////////////////////////////////////////////////// // // Find_Value_Index // ///////////////////////////////////////////////////////////////////////////// int VisErrorReportDialogClass::Find_Value_Index (float fraction) { /*int retval = -1; // // Simple binary search to find the right place // to insert the new data point // int start = 0; int end = m_PointList.Count () - 1; while ((end > start) && (retval == -1)) { int index = start + ((end - start) >> 1); float curr_fraction = m_PointList[index]->BackfaceFraction; if (index == start) { retval = (fraction > curr_fraction) ? end : start; break; } else if (fraction > curr_fraction) { start = index; } else if (fraction < curr_fraction) { end = index; } else { retval = index; } } if (retval == -1) { retval = start; }*/ int start = 0; int end = m_PointList.Count (); end = max (end, 0); int index = end; while (end > start) { index = start + ((end - start) >> 1); float curr_fraction = m_PointList[index]->Get_Biggest_Fraction (); if (fraction > curr_fraction) { if (start == index) { index ++; break; } start = index; } else if (fraction < curr_fraction) { if (end == index) { index --; break; } end = index; } else { while ((curr_fraction == fraction) && (index > 0)) { curr_fraction = m_PointList[--index]->Get_Biggest_Fraction (); } index = (curr_fraction == fraction) ? index : index + 1; //m_ValueList[index].count ++; //found = true; break; } } ASSERT (index >=0 ); return index; } ////////////////////////////////////////////////////////////////////////////////// // // On_Graph_Sel_Changed // ////////////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::On_Graph_Sel_Changed (void) { float range_min = 0; float range_max = 0; m_Graph.Get_Selection (range_min, range_max); if (range_min >= 0 && range_max >= 0) { m_SelStartIndex = Find_Value_Index (range_min); m_SelEndIndex = Find_Value_Index (range_max); } else { m_SelStartIndex = 0; m_SelEndIndex = m_PointList.Count () - 1; m_SelEndIndex = max (m_SelEndIndex, 0); } m_CurrentPoint = m_SelStartIndex - 1; // // Update the dialog UI // Update_Current_Point_Text (); Update_Nav_Buttons (); return ; } ////////////////////////////////////////////////////////////////////////////////// // // Update_Nav_Buttons // ////////////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::Update_Nav_Buttons (void) { bool enable_prev = m_CurrentPoint > m_SelStartIndex; bool enable_next = (m_CurrentPoint < m_SelEndIndex) && (m_PointList.Count () > 0); ::EnableWindow (::GetDlgItem (m_hWnd, IDC_PREV_ERROR), enable_prev); ::EnableWindow (::GetDlgItem (m_hWnd, IDC_NEXT_ERROR), enable_next); return ; } ////////////////////////////////////////////////////////////////////////////////// // // OnPrevError // ////////////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::OnPrevError (void) { if (m_CurrentPoint > m_SelEndIndex) { m_CurrentPoint = m_SelEndIndex; } else { m_CurrentPoint --; m_CurrentPoint = max (m_CurrentPoint, 0); } // // Show the point // if (m_CurrentPoint < m_PointList.Count ()) { VisSampleClass *vis_sample = m_PointList[m_CurrentPoint]; int index = vis_sample->Get_Biggest_Fraction_Index (); vis_sample->Set_Cur_Direction ((VisDirType)index); Display_Point (vis_sample->Get_Camera_Transform ((VisDirType)index), true); } // // Update the UI // Update_Current_Point_Text (); Update_Nav_Buttons (); return ; } ////////////////////////////////////////////////////////////////////////////////// // // OnNextError // ////////////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::OnNextError (void) { if (m_CurrentPoint < m_SelStartIndex) { m_CurrentPoint = m_SelStartIndex; } else { m_CurrentPoint ++; m_CurrentPoint = min (m_CurrentPoint, m_PointList.Count () - 1); } // // Show the point // if (m_CurrentPoint < m_PointList.Count ()) { VisSampleClass *vis_sample = m_PointList[m_CurrentPoint]; int index = vis_sample->Get_Biggest_Fraction_Index (); vis_sample->Set_Cur_Direction ((VisDirType)index); Display_Point (vis_sample->Get_Camera_Transform ((VisDirType)index), true); } // // Update the UI // Update_Current_Point_Text (); Update_Nav_Buttons (); return ; } ////////////////////////////////////////////////////////////////////////////////// // // Update_Current_Point_Text // ////////////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::Update_Current_Point_Text (void) { // // Update the point-range static text control // int current_point = max ((m_CurrentPoint - m_SelStartIndex) + 1, 0); CString message; message.Format ("%d of %d", current_point, m_SelEndIndex - m_SelStartIndex); SetDlgItemText (IDC_CURRENT_POINT, message); if ((m_CurrentPoint >= 0) && (m_CurrentPoint < m_PointList.Count ())) { VisSampleClass *vis_sample = m_PointList[m_CurrentPoint]; // // Update the backface percent for this sample // float fraction = vis_sample->Get_Biggest_Fraction (); message.Format ("%.2f %%", fraction * 100); SetDlgItemText (IDC_CURRENT_PERCENT, message); // // Get the status string for the current direction // int dir_index = vis_sample->Get_Cur_Direction (); switch (vis_sample->Sample_Status ((VisDirType)dir_index)) { case VIS_STATUS_OK: message = "Ok"; break; case VIS_STATUS_NOT_TAKEN: message = "Not Taken"; break; case VIS_STATUS_ERROR: message = "!!Error!!"; break; case VIS_STATUS_BACKFACE_LEAK: message = "Leak"; break; case VIS_STATUS_BACKFACE_OVERFLOW: message = "Overflow"; break; } SetDlgItemText (IDC_CURRENT_POINT_STATUS, message); } else { SetDlgItemText (IDC_CURRENT_PERCENT, ""); SetDlgItemText (IDC_CURRENT_POINT_STATUS, ""); } return ; } ///////////////////////////////////////////////////////////////////////////// // // OnDrawItem // ///////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::OnDrawItem ( int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct ) { // // Determine what state to draw the button in (pushed or normal) // UINT state = DFCS_BUTTONPUSH | DFCS_ADJUSTRECT; POINT offset = { 0 }; if (lpDrawItemStruct->itemState & ODS_SELECTED) { state |= DFCS_PUSHED; offset.x = 1; offset.y = 1; } // Draw the button's outline CRect rect = lpDrawItemStruct->rcItem; ::DrawFrameControl (lpDrawItemStruct->hDC, rect, DFC_BUTTON, state); // // Determine which BMP to use // HBITMAP hbmp = NULL; if (nIDCtl == IDC_PREV_ERROR) { hbmp = ::IsWindowEnabled (lpDrawItemStruct->hwndItem) ? m_PrevButton.normal : m_PrevButton.disabled; } else if (nIDCtl == IDC_NEXT_ERROR) { hbmp = ::IsWindowEnabled (lpDrawItemStruct->hwndItem) ? m_NextButton.normal : m_NextButton.disabled; } HDC mem_dc = ::CreateCompatibleDC (NULL); HBITMAP old_bmp = (HBITMAP)::SelectObject (mem_dc, hbmp); // // Draw the BMP centered in the button // const int BMP_WIDTH = 25; const int BMP_HEIGHT = 28; int x_pos = rect.left + (rect.Width () >> 1) - (BMP_WIDTH >> 1) + offset.x; int y_pos = rect.top + (rect.Height () >> 1) - (BMP_HEIGHT >> 1) + offset.y; ::BitBlt (lpDrawItemStruct->hDC, x_pos, y_pos, BMP_WIDTH, BMP_HEIGHT, mem_dc, 0, 0, SRCCOPY); ::SelectObject (mem_dc, old_bmp); ::DeleteDC (mem_dc); // Draw the focus rectangle if necessary if (lpDrawItemStruct->itemState & ODS_FOCUS) { ::DrawFocusRect (lpDrawItemStruct->hDC, &rect); } // Allow the base class to process this message CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct); return ; } ///////////////////////////////////////////////////////////////////////////// // // Paint_Axis_Area // ///////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::Paint_Axis_Area (HDC hdc) { HDC mem_dc = ::CreateCompatibleDC (NULL); HBITMAP old_bmp = (HBITMAP)::SelectObject (mem_dc, m_AxisBMP); // // Draw the BMP centered in the button // const int BMP_WIDTH = 65; const int BMP_HEIGHT = 65; //int x_pos = m_AxisArea.left + (m_AxisArea.Width () >> 1) - (BMP_WIDTH >> 1); //int y_pos = m_AxisArea.top + (m_AxisArea.Height () >> 1) - (BMP_HEIGHT >> 1); ::BitBlt (hdc, m_AxisArea.left, m_AxisArea.top, BMP_WIDTH, BMP_HEIGHT, mem_dc, 0, 0, SRCCOPY); ::SelectObject (mem_dc, old_bmp); old_bmp = (HBITMAP)::SelectObject (mem_dc, m_AxisSelBMP); // // Paint the selected areas of the axis // for (int index = 0; index < 6; index ++) { if (m_AxisSel & (1 << index)) { CRect &rect = m_AxisSelAreas[index]; int x_pos = m_AxisArea.left + rect.left; int y_pos = m_AxisArea.top + rect.top; ::BitBlt (hdc, x_pos, y_pos, rect.Width (), rect.Height (), mem_dc, rect.left, rect.top, SRCCOPY); } } ::SelectObject (mem_dc, old_bmp); ::DeleteDC (mem_dc); return ; } UINT VisErrorReportDialogClass::OnNcHitTest(CPoint point) { // TODO: Add your message handler code here and/or call default return CDialog::OnNcHitTest(point); } ///////////////////////////////////////////////////////////////////////////// // // OnSetCursor // ///////////////////////////////////////////////////////////////////////////// BOOL VisErrorReportDialogClass::OnSetCursor ( CWnd * pwnd, UINT hit_test, UINT message ) { BOOL retval = FALSE; // // Determine if the cursor is over a 'hot-spot' in the axis area. // if (Update_Axis_Area ()) { ::SetCursor (::LoadCursor (::AfxGetResourceHandle (), MAKEINTRESOURCE (IDC_HAND_POINTER))); } else { retval = CDialog::OnSetCursor (pwnd, hit_test, message); } return retval; } ///////////////////////////////////////////////////////////////////////////// // // Update_Axis_Area // ///////////////////////////////////////////////////////////////////////////// bool VisErrorReportDialogClass::Update_Axis_Area (bool do_view_change) { CPoint point; ::GetCursorPos (&point); ScreenToClient (&point); point.x -= m_AxisArea.left; point.y -= m_AxisArea.top; bool found = false; int old_sel = m_AxisSel; m_AxisSel = 0; // // Only do the UI stuff if we have a current point. // if ((m_CurrentPoint >= 0) && (m_CurrentPoint < m_PointList.Count ())) { VisSampleClass *vis_sample = m_PointList[m_CurrentPoint]; if ((point.x >= 0) && (point.y >= 0)) { // // Determine which direction we are over (if any) // for (int index = 0; index < 6 && !found; index ++) { if (m_AxisSelAreas[index].PtInRect (point)) { m_AxisSel |= (1 << index); found = true; // // Update the camera if necessary // if (do_view_change) { vis_sample->Set_Cur_Direction ((VisDirType)index); Display_Point (vis_sample->Get_Camera_Transform ((VisDirType)index), false); } } } } // // Hilight the direction that is currently displayed // int direction = vis_sample->Get_Cur_Direction (); int bit = (1 << direction); m_AxisSel |= bit; } if (old_sel != m_AxisSel) { // // Repaint the axis area // HDC hdc = ::GetDC (m_hWnd); Paint_Axis_Area (hdc); ::ReleaseDC (m_hWnd, hdc); } return found; } ///////////////////////////////////////////////////////////////////////////// // // OnDestroy // ///////////////////////////////////////////////////////////////////////////// void VisErrorReportDialogClass::OnDestroy (void) { CDialog::OnDestroy(); ::RemoveProp (m_hWnd, "ALLOW_UPDATE"); return ; }