home *** CD-ROM | disk | FTP | other *** search
/ Using Visual Basic 5 (Platinum Edition) / vb5.iso / ACTIVEX / SRDVID / DATA.Z / csurview.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-10  |  19.3 KB  |  730 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // CSurView.cpp : Implementation of the CSurroundView class
  4. //
  5. /////////////////////////////////////////////////////////////////////////////
  6. //
  7. //  (C) Copyright Black Diamond Consulting, Inc 1996. All rights reserved.
  8. //
  9. //    You have a royalty-free right to use, modify, reproduce and 
  10. //    distribute the Sample Files (and/or any modified version) in 
  11. //    any way you find useful, provided that you agree that Black 
  12. //    Diamond Consulting has no warranty obligations or liability
  13. //    for any Sample Application Files which are modified. 
  14. //
  15. //    Revision History:
  16. //
  17. /////////////////////////////////////////////////////////////////////////////
  18.  
  19. #include "stdafx.h"
  20. #include "dib.h"
  21. #include "resource.h"
  22.  
  23. #ifndef _Surround_H_
  24.     #include "Surround.h"
  25. #endif
  26.  
  27. #ifndef __CSURVIEW_H__
  28.     #include "CSurView.h"
  29. #endif
  30.  
  31. #ifdef _DEBUG
  32.     #undef THIS_FILE
  33.     static char BASED_CODE THIS_FILE[] = __FILE__;
  34. #endif
  35.  
  36. #define LOSHORT(l)    ((SHORT)(l))
  37. #define HISHORT(l)    ((SHORT)(((DWORD)(l) >> 16) & 0xFFFF))
  38.  
  39. /////////////////////////////////////////////////////////////////////////////
  40. // CSurroundView
  41. IMPLEMENT_DYNAMIC( CSurroundView, CView )
  42.  
  43. BEGIN_MESSAGE_MAP( CSurroundView, CView )
  44.     //{{AFX_MSG_MAP(CSurroundView)
  45.     ON_WM_TIMER()
  46.     ON_WM_SETCURSOR()    
  47.     ON_WM_LBUTTONDOWN()
  48.     ON_WM_KEYDOWN()
  49.     ON_WM_ERASEBKGND()
  50.     ON_WM_SIZE()
  51.     //}}AFX_MSG_MAP
  52. END_MESSAGE_MAP()
  53.  
  54. /////////////////////////////////////////////////////////////////////////////
  55. // CSurroundView construction/destruction
  56. CSurroundView::CSurroundView()
  57. {
  58.      m_pSV = NULL;                    // No View
  59.     m_hPalette = NULL;                // No palette
  60.     m_hOffscreenBitmap = NULL;        // No offscreen bitmap
  61.  
  62.     m_zoomInKey    = VK_SHIFT;            // Default zoom in key
  63.     m_zoomOutKey = VK_CONTROL;        // Default zoom out key
  64.  
  65.     this->Reset();
  66. }
  67.  
  68. CSurroundView::~CSurroundView()
  69. {
  70.     this->Reset();
  71. }
  72.  
  73. void CSurroundView::Reset()
  74. {
  75.     // Release any view we may have
  76.     if( m_pSV != NULL )
  77.     {
  78.         m_pSV->Release( );
  79.         m_pSV = NULL;
  80.     }
  81.  
  82.     // Delete possible palette
  83.     if( m_hPalette != NULL )
  84.     {
  85.         DeleteObject( m_hPalette );
  86.         m_hPalette = NULL;
  87.     }
  88.  
  89.     // Delete possible offscreen bitmap
  90.     if( m_hOffscreenBitmap != NULL )
  91.     {
  92.          DeleteObject( m_hOffscreenBitmap );
  93.         m_hOffscreenBitmap = NULL;
  94.     }
  95.  
  96.     // Set default location
  97.     m_location.longitude = 0;
  98.     m_location.latitude = 0;
  99.     
  100.     // Size of view
  101.     m_size.cx = m_size.cy = 0;
  102.     
  103.     // Zoom Ratio of 1
  104.     m_fZoom    = 1.0f;                    
  105.  
  106.     // Set default cursor
  107.     m_cursorID = 0;
  108.  
  109. }
  110.  
  111. void CSurroundView::SetZoomKeys( int zoomInKey, int zoomOutKey )
  112. {
  113.     m_zoomInKey = zoomInKey;
  114.     m_zoomOutKey = zoomOutKey;
  115. }
  116.  
  117. void CSurroundView::OnDraw(CDC* pDC)
  118. {
  119.     CRect rect;
  120.     CRect rectSrc;
  121.     HDC hdc;
  122.  
  123.     // If we don't have a view, just paint the background black
  124.     if( m_pSV == NULL )
  125.     {
  126.         GetClientRect( &rect );
  127.         pDC->FillRect( rect, CBrush::FromHandle((HBRUSH)::GetStockObject(BLACK_BRUSH)) );
  128.         return;
  129.     }
  130.  
  131.     if( m_viewExtents.right == MAX_ARCSECONDS ) // 360 image
  132.     {
  133.         if (m_location.longitude < 0)
  134.             m_location.longitude = MAX_ARCSECONDS + (m_location.longitude % MAX_ARCSECONDS);
  135.         else if (m_location.longitude > MAX_ARCSECONDS)
  136.             m_location.longitude %= MAX_ARCSECONDS;
  137.     }
  138.     else // < 360 image
  139.     {
  140.         // Range check horizontal pan
  141.         if( m_location.longitude < m_viewExtents.left )
  142.             m_location.longitude = m_viewExtents.left;
  143.         else if( m_location.longitude > m_viewExtents.right )
  144.             m_location.longitude = m_viewExtents.right;
  145.     }
  146.  
  147.     // Range check vertical pan
  148.     if( m_location.latitude < m_viewExtents.top )
  149.         m_location.latitude = m_viewExtents.top;
  150.     else if( m_location.latitude > m_viewExtents.bottom )
  151.         m_location.latitude = m_viewExtents.bottom;
  152.  
  153.     hdc = pDC->GetSafeHdc();
  154.  
  155.     // If we are using a palette, realize it
  156.     if( m_hPalette != NULL )
  157.     {
  158.          ::SelectPalette( hdc, m_hPalette, FALSE );
  159.         ::RealizePalette( hdc );
  160.     }
  161.  
  162.     // Paint the image into our offscreen bitmap
  163.     rect.SetRect( 0, 0, m_offscreenInfo.header.biWidth, m_offscreenInfo.header.biHeight );
  164.     m_pSV->Draw( &m_location, &m_offscreenInfo.header, m_pOffscreenBits, &rect, 100 );
  165.  
  166.     GetClientRect( &rect );
  167.  
  168.     if( m_fZoom == 1.0 )
  169.     {
  170.         rectSrc = rect;
  171.     }
  172.     else
  173.     {
  174.         float newHeight = ((float)rect.Height()) / m_fZoom;
  175.         float newWidth = ((float)rect.Width()) / m_fZoom;
  176.  
  177.         rectSrc.top = rect.top + (long)(((float)rect.Height() - newHeight) / 2);
  178.         rectSrc.left = rect.left + (long)(((float)rect.Width() - newWidth) / 2);
  179.         rectSrc.bottom = rectSrc.top + (long)newHeight;
  180.         rectSrc.right = rectSrc.left + (long)newWidth;
  181.     }    
  182.  
  183.     StretchDIBits( hdc, rect.left, rect.top, rect.Width(), rect.Height(),
  184.                    rectSrc.left, rectSrc.top, rectSrc.Width(), rectSrc.Height(),
  185.                    m_pOffscreenBits, (BITMAPINFO *)&m_offscreenInfo, DIB_RGB_COLORS, SRCCOPY );
  186. }
  187.  
  188. HPALETTE CSurroundView::CreateIdentityPalette( int nColors )
  189. {
  190.     int i;
  191.     int nStaticColors;
  192.     int nUsableColors;
  193.  
  194.     //*** Initialize version number and # entries
  195.     m_logicalPalette.version = 0x300;
  196.     m_logicalPalette.numberOfEntries = 256;
  197.  
  198.     //*** Just use the screen DC where we need it
  199.     HDC hdc = ::GetDC( NULL );
  200.  
  201.     //*** For SYSPAL_NOSTATIC, just copy the color table into
  202.     //*** a PALETTEENTRY array and replace the first and last entries
  203.     //*** with black and white
  204.     //*** For SYSPAL_STATIC, get the twenty static colors into
  205.     //*** the array, then fill in the empty spaces with the
  206.     //*** given color table
  207.  
  208.     //*** Get the static colors from the system palette
  209.  
  210.     // if (GetSystemPaletteUse(hdc) == SYSPAL_NOSTATIC)
  211.     if( TRUE )
  212.         nStaticColors = 0;
  213.     else
  214.         nStaticColors = ::GetDeviceCaps( hdc, NUMCOLORS ) / 2;
  215.         
  216.     if( nStaticColors > 0 )
  217.     {
  218.         ::GetSystemPaletteEntries( hdc, 0, nStaticColors, m_logicalPalette.entries );
  219.         ::GetSystemPaletteEntries( hdc, 256-nStaticColors, nStaticColors, m_logicalPalette.entries );
  220.     }
  221.  
  222.     for( i = 0; i < nStaticColors; i++ )
  223.         m_logicalPalette.entries[i].peFlags = 0;
  224.  
  225.     for( i = 0;i < nStaticColors; i++ )
  226.     {
  227.         // copy the system colors into the DIB header
  228.         m_offscreenInfo.colors[i].rgbRed =
  229.                 m_logicalPalette.entries[i].peRed;
  230.         m_offscreenInfo.colors[i].rgbGreen =
  231.                 m_logicalPalette.entries[i].peGreen;
  232.         m_offscreenInfo.colors[i].rgbBlue =
  233.                 m_logicalPalette.entries[i].peBlue;
  234.         m_offscreenInfo.colors[i].rgbReserved = 0;
  235.  
  236.         m_logicalPalette.entries[i].peFlags = 0;
  237.  
  238.         m_offscreenInfo.colors[256 - i].rgbRed =
  239.               m_logicalPalette.entries[256 - i].peRed;
  240.         m_offscreenInfo.colors[256 - i].rgbGreen =
  241.               m_logicalPalette.entries[256 - i].peGreen;
  242.         m_offscreenInfo.colors[256 - i].rgbBlue =
  243.               m_logicalPalette.entries[256 - i].peBlue;
  244.         m_offscreenInfo.colors[256 - i].rgbReserved = 0;
  245.  
  246.         m_logicalPalette.entries[256 - i].peFlags = 0;
  247.     }
  248.  
  249.     //*** Fill in the entries from the given color table
  250.     nUsableColors = nColors - nStaticColors;
  251.  
  252.     if( m_pSV != NULL )
  253.         m_pSV->GetColors( i, nUsableColors, m_offscreenInfo.colors );
  254.  
  255.     for( ; i < nUsableColors; i++ )
  256.     {
  257.         m_logicalPalette.entries[i].peRed = m_offscreenInfo.colors[i].rgbRed;
  258.         m_logicalPalette.entries[i].peGreen = m_offscreenInfo.colors[i].rgbGreen;
  259.         m_logicalPalette.entries[i].peBlue = m_offscreenInfo.colors[i].rgbBlue;
  260.         m_offscreenInfo.colors[i].rgbReserved = 0;
  261.         m_logicalPalette.entries[i].peFlags = PC_NOCOLLAPSE;
  262.     }
  263.  
  264.     //*** Mark any empty entries as PC_NOCOLLAPSE
  265.     for( ; i < 256 - nStaticColors; i++ )
  266.         m_logicalPalette.entries[i].peFlags = PC_NOCOLLAPSE;
  267.  
  268.     //*** Set the peFlags of the upper static colors to zero
  269.     for( i = 256 - nStaticColors; i < 256; i++ )
  270.         m_logicalPalette.entries[i].peFlags = 0;
  271.  
  272.     //*** Remember to release the DC!
  273.     ::ReleaseDC( NULL, hdc );
  274.  
  275.     //*** Return the palette
  276.     return ::CreatePalette( (LOGPALETTE *)&m_logicalPalette );
  277. }
  278.  
  279. // GetMaxViewSize()
  280. //
  281. //    Returns the maximum size of the client window for the current
  282. //    Surround Video Image
  283. //
  284. void CSurroundView::GetMaxViewSize( SIZE* pSize )
  285. {
  286.     ISurround* pISurround = this->GetISurround();
  287.  
  288.     if( pISurround != NULL )
  289.         pISurround->GetMaxViewSize( 1.0f, pSize );
  290.     else
  291.     {    
  292.         pSize->cx = ::GetSystemMetrics( SM_CXFULLSCREEN );
  293.         pSize->cy = ::GetSystemMetrics( SM_CYFULLSCREEN );
  294.     }
  295. }
  296.  
  297. BOOL CSurroundView::UpdateSurroundView()
  298. {
  299.     CRect clientRect;
  300.     SIZE maxViewSize;
  301.     
  302.     // Make sure there is an ISurround
  303.     if( this->GetISurround() == NULL )
  304.         return FALSE;
  305.     
  306.     // If we already have a view, release it
  307.     if( m_pSV != NULL )
  308.     {
  309.         m_pSV->Release( );
  310.         m_pSV = NULL;
  311.     }
  312.  
  313.     // Calculate our view size based on current window size and max view size
  314.     this->GetISurround()->GetMaxViewSize( 1.0f, &maxViewSize );
  315.     GetClientRect( clientRect );
  316.     m_size.cx = min( clientRect.Width(), maxViewSize.cx );
  317.     m_size.cy = min( clientRect.Height(), maxViewSize.cy );
  318.  
  319.     this->GetISurround()->GetView( &m_size, 1.0f, 100, SV_TOTAL_CORRECTION, &m_pSV );
  320.  
  321.     if( m_pSV != NULL )
  322.     {
  323.         // Make sure our current location is valid
  324.         // NOTE: The call to GetViewRange also sets our location to the center (horizon) of the image
  325.         m_pSV->GetViewRange( &m_viewExtents, &m_location.latitude );
  326.  
  327.         if( m_location.longitude < m_viewExtents.left )
  328.             m_location.longitude = m_viewExtents.left;
  329.         else if( m_location.longitude > m_viewExtents.right )
  330.             m_location.longitude = m_viewExtents.right;
  331.  
  332.         this->UpdateOffscreenBitmap();
  333.     
  334.     }
  335.  
  336.     return m_pSV != NULL;
  337. }
  338.  
  339. void CSurroundView::UpdateOffscreenBitmap()
  340. {
  341.  
  342.     // Makes no sense if we don't have a view
  343.     if( m_pSV == NULL )
  344.         return;
  345.  
  346.     SIZE size;
  347.     HDC hdc = ::GetDC( m_hWnd );
  348.  
  349.     // Delete any previous bitmap
  350.     if( m_hOffscreenBitmap != NULL )
  351.         DeleteObject( m_hOffscreenBitmap );
  352.     
  353.     // Get the size of the view
  354.     m_pSV->GetSize( &size );
  355.  
  356.     // Initialize offscreen bitmap
  357.     m_offscreenInfo.header.biSize = sizeof(BITMAPINFOHEADER);
  358.     m_offscreenInfo.header.biPlanes = 1;
  359.     m_offscreenInfo.header.biBitCount = m_pSV->GetDepth();
  360.     m_offscreenInfo.header.biCompression = BI_RGB;
  361.     m_offscreenInfo.header.biClrUsed = 0;
  362.     m_offscreenInfo.header.biClrImportant = 0;
  363.     m_offscreenInfo.header.biHeight = size.cy;
  364.     m_offscreenInfo.header.biWidth = size.cx;
  365.     m_offscreenInfo.header.biSizeImage = (DWORD)DibPitch(&m_offscreenInfo.header) *
  366.                                          (DWORD)DibHeight(&m_offscreenInfo.header);
  367.  
  368.     // Note: Here we create an identity palette for images with 8 bits/pixel or less.
  369.     //         If the image is greater than 8 bits/pixel we don't need a palette unless
  370.     //         we have an 8 bit (or lower) display, in which case we use the system
  371.     //         halftone palette.
  372.     if( m_hPalette != NULL )
  373.     {
  374.         DeleteObject(m_hPalette);
  375.         m_hPalette = NULL;
  376.     }
  377.     if( m_offscreenInfo.header.biBitCount == 8 )
  378.         m_hPalette = CreateIdentityPalette( 256 );
  379.     else
  380.     {
  381.         if( GetDeviceCaps( hdc, BITSPIXEL ) <= 8 )
  382.             m_hPalette = ::CreateHalftonePalette( hdc );
  383.     }
  384.         
  385.     // Create the offscreen bitmap
  386.     m_hOffscreenBitmap = CreateDIBSection( hdc, (BITMAPINFO*)&m_offscreenInfo, DIB_RGB_COLORS,
  387.                                            &m_pOffscreenBits, NULL, 0 );
  388.     ::ReleaseDC( m_hWnd, hdc );
  389. }
  390.  
  391.  
  392. void CSurroundView::OnInitialUpdate() 
  393. {
  394.     CView::OnInitialUpdate();
  395.  
  396.     this->Reset();
  397.     this->UpdateSurroundView();
  398.  
  399.     // Force OnGetMinMaxInfo of parent frame to get called.
  400.     // this will cause us to get sized appropriately if need be
  401.     RECT rect;
  402.     this->GetParentFrame()->GetWindowRect( &rect );
  403.     this->GetParentFrame()->MoveWindow( &rect, TRUE );
  404.  
  405. }
  406.  
  407. afx_msg void CSurroundView::OnSize(UINT nType, int cx, int cy) 
  408. {
  409.     CView::OnSize(nType, cx, cy);
  410.     this->UpdateSurroundView();
  411. }
  412.  
  413. afx_msg BOOL CSurroundView::OnEraseBkgnd( CDC* pDC ) 
  414. {
  415.     if( IsViewPresent() )
  416.         return TRUE;
  417.  
  418.     RECT rect;
  419.     GetClientRect( &rect );
  420.     pDC->FillRect( &rect, CBrush::FromHandle((HBRUSH)::GetStockObject(BLACK_BRUSH)) );
  421.     return TRUE;
  422. }
  423.  
  424. afx_msg void CSurroundView::OnKeyDown( UINT nChar, UINT nRepCnt, UINT nFlags )
  425. {
  426.     CView::OnKeyDown( nChar, nRepCnt, nFlags );    
  427.  
  428.     float zoomIncrement = 1.02F;
  429.  
  430.     if( nChar == m_zoomInKey )
  431.     {
  432.         m_fZoom *= zoomIncrement;
  433.     }
  434.     else if (nChar == m_zoomOutKey)
  435.     {
  436.         m_fZoom /= zoomIncrement;
  437.     }
  438.     else
  439.         return;
  440.  
  441.     if( m_fZoom >= 1.0F )
  442.         this->Invalidate(FALSE);
  443.     else
  444.         m_fZoom = 1.0F;
  445.  
  446. }
  447.  
  448. void CSurroundView::ScrollImage( CPoint &anchorPoint, BOOL bLeftButton /* = TRUE */ )
  449. {
  450.     MSG msg;
  451.     CSize szDistance;
  452.      
  453.      // Set the anchor point
  454.     m_anchorPoint = anchorPoint;
  455.     ClientToScreen( &m_anchorPoint );
  456.  
  457.     // We are initially at Rest
  458.     ::SetCursor( AfxGetApp()->LoadCursor(m_cursorID = IDC_REST) );
  459.      szDistance.cx = 0;
  460.     szDistance.cy = 0;
  461.  
  462.     // Capture the mouse
  463.     SetCapture();
  464.  
  465.     // trap messages here until capture is lost or cancelled/accepted
  466.     while( 1 )
  467.     {
  468.         if( ::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
  469.         {
  470.             if( msg.message == WM_MOUSEMOVE )
  471.             {
  472.                 CPoint    ptCurrent;
  473.                 UINT    oldCursorID;
  474.  
  475.                 // If left mouse button isn't down, we're not suppose to be here
  476.                 if( !(msg.wParam & ((bLeftButton) ? MK_LBUTTON : MK_RBUTTON) ) )
  477.                     return;
  478.  
  479.                 // Save the current cursor ID
  480.                 oldCursorID = m_cursorID;
  481.  
  482.                 // Set current mouse point (We need signed values here)
  483.                 ptCurrent.x    = LOSHORT(msg.lParam);
  484.                 ptCurrent.y    = HISHORT(msg.lParam);
  485.                 ClientToScreen(&ptCurrent);
  486.  
  487.                 if(m_anchorPoint.x == -1 && m_anchorPoint.y == -1)
  488.                 {
  489.                     m_cursorID = 0;
  490.                     szDistance.cx = 0;
  491.                     szDistance.cy = 0;
  492.                 }
  493.                 else
  494.                 {
  495.                     BOOL bCloseToXAxis = FALSE;
  496.                     BOOL bCloseToYAxis = FALSE;
  497.  
  498.                     szDistance.cx = ptCurrent.x - m_anchorPoint.x;
  499.                     szDistance.cy = ptCurrent.y - m_anchorPoint.y;
  500.  
  501.                      if( szDistance.cx == 0 && szDistance.cy == 0 )
  502.                         m_cursorID = IDC_REST;
  503.                     else
  504.                      {
  505.                          if( abs(szDistance.cx) < abs(szDistance.cy) )
  506.                             bCloseToYAxis = ( 5 * abs(szDistance.cx) < 2 * abs(szDistance.cy) );
  507.                         else if( abs(szDistance.cx) > abs(szDistance.cy) )
  508.                             bCloseToXAxis = (5 * abs(szDistance.cy) < 2 * abs(szDistance.cx) );
  509.  
  510.                          if( bCloseToXAxis )
  511.                             m_cursorID = (szDistance.cx > 0) ? IDC_RIGHT : IDC_LEFT;
  512.                         else if(bCloseToYAxis)
  513.                             m_cursorID = (szDistance.cy > 0) ? IDC_DOWN : IDC_UP;
  514.                         else if( ptCurrent.x < m_anchorPoint.x )
  515.                             m_cursorID = ( ptCurrent.y < m_anchorPoint.y ) ? IDC_UL : IDC_DL;
  516.                         else if(ptCurrent.x > m_anchorPoint.x)
  517.                             m_cursorID = ( ptCurrent.y < m_anchorPoint.y ) ? IDC_UR : IDC_DR;
  518.                     }
  519.                 }
  520.  
  521.                 // Change cursor if we need to
  522.                 if( m_cursorID != oldCursorID )
  523.                     ::SetCursor( AfxGetApp()->LoadCursor(m_cursorID) );
  524.             }
  525.             else if( msg.message == (UINT)((bLeftButton) ? WM_LBUTTONUP : WM_RBUTTONUP) )
  526.             {
  527.                 ReleaseCapture();
  528.                 m_cursorID = 0;
  529.                 return;
  530.             }
  531.             else
  532.             {
  533.                 DispatchMessage(&msg);
  534.             }
  535.  
  536.         } // if( PeekMessage() )
  537.  
  538.         // If we need to move the image, do it
  539.         if( szDistance.cx != 0 || szDistance.cy != 0 )
  540.         {
  541.             m_location.longitude += (ARCSECONDS)(((szDistance.cx * 120)/m_fZoom));
  542.             m_location.latitude += (ARCSECONDS)(((szDistance.cy * (-120))/m_fZoom));
  543.  
  544.             CDC* pDC = GetDC();
  545.             if( pDC != NULL )
  546.             {
  547.                 this->OnDraw( pDC );
  548.                 ReleaseDC( pDC );
  549.             }
  550.         }
  551.  
  552.     } // end while( TRUE )
  553. }
  554.  
  555. afx_msg void CSurroundView::OnLButtonDown( UINT nFlags, CPoint point )
  556. {
  557.     // Scroll the image
  558.     ScrollImage( point );
  559. }
  560.  
  561. afx_msg BOOL CSurroundView::OnSetCursor( CWnd* pWnd, UINT nHitTest, UINT message )
  562. {
  563.     if( m_cursorID != 0 )
  564.     {
  565.         ::SetCursor( AfxGetApp()->LoadCursor( m_cursorID ) );
  566.         return TRUE;
  567.     }
  568.     return CView::OnSetCursor( pWnd, nHitTest, message );
  569. }
  570.  
  571.  
  572. HRESULT CSurroundView::SphereToView( LPSPHERE_POINT pLocation, LPPOINT pPoint )
  573. {
  574.     if( m_pSV == NULL )
  575.         return SV_E_INCOMPATIBLE_SURFACE;
  576.  
  577.     return m_pSV->SphereToView( pLocation, &m_location, pPoint );
  578. }
  579.  
  580. HRESULT CSurroundView::SphereToView( LPSPHERE_POINT pLocation, LPSIZE pSize, LPRECT pRect )
  581. {
  582.     HRESULT hr;
  583.     POINT pt;
  584.  
  585.     if( m_pSV == NULL )
  586.         return SV_E_INCOMPATIBLE_SURFACE;
  587.  
  588.     hr = m_pSV->SphereToView( pLocation, &m_location, &pt );
  589.     if( FAILED(hr) )
  590.         return hr;
  591.     
  592.     pt.x += m_size.cx >> 1;
  593.     pt.y += m_size.cy >> 1;
  594.  
  595.     // Calculate the location of pRect in view coordinates
  596.     pRect->top = pt.y - pSize->cy/2;
  597.     pRect->left = pt.x - pSize->cx/2;
  598.  
  599.     // ...figure in the zoom factor
  600.     pRect->left = (LONG)((float)m_size.cx*0.5F*(1.0F - m_fZoom)+m_fZoom*(float)pRect->left);
  601.     pRect->top = (LONG)((float)m_size.cy*0.5F*(1.0F - m_fZoom)+m_fZoom*(float)pRect->top);
  602.  
  603.     // ...and finally, the size of the rect
  604.     pRect->right = pRect->left + (LONG)((float)pSize->cx * m_fZoom);
  605.     pRect->bottom = pRect->top + (LONG)((float)pSize->cy * m_fZoom);
  606.  
  607.     return S_OK;
  608. }
  609.  
  610. HRESULT CSurroundView::ViewToSphere( LPPOINT pPoint, LPSPHERE_POINT pLocation )
  611. {
  612.     if( m_pSV == NULL )
  613.         return SV_E_INCOMPATIBLE_SURFACE;
  614.  
  615.     return m_pSV->ViewToSphere( pPoint, &m_location, pLocation );
  616. }
  617.  
  618. HRESULT CSurroundView::ViewToSphere( LPRECT pRect, LPSPHERE_POINT pLocation, LPSIZE pSize )
  619. {
  620.     POINT pt;
  621.  
  622.     if( m_pSV == NULL )
  623.         return SV_E_INCOMPATIBLE_SURFACE;    
  624.  
  625.     pSize->cx = (LONG)((float)(pRect->right - pRect->left) / m_fZoom);
  626.     pSize->cy = (LONG)((float)(pRect->bottom - pRect->top) / m_fZoom);
  627.  
  628.     pRect->left = (LONG)(((float)pRect->left - (float)m_size.cx*0.5F*(1.0F - m_fZoom))/m_fZoom);
  629.     pRect->top = (LONG)(((float)pRect->top - (float)m_size.cy*0.5F*(1.0F - m_fZoom))/m_fZoom);
  630.  
  631.     pt.x = pRect->left + pSize->cx / 2;
  632.     pt.y = pRect->top + pSize->cy / 2;
  633.  
  634.     pt.x -= m_size.cx / 2;
  635.     pt.y -= m_size.cy / 2;
  636.  
  637.     return m_pSV->ViewToSphere( &pt, &m_location, pLocation );
  638. }
  639.  
  640. HGLOBAL CSurroundView::GetImage( LPSPHERE_POINT pLocation, LPSIZE pSize )
  641. {
  642.     HGLOBAL hMemory;
  643.     DWORD memSize;
  644.     UINT depth;
  645.     BITMAPINFOHEADER* pDib;
  646.     ISurround* pISurround = this->GetISurround();
  647.  
  648.     if( pISurround == NULL )
  649.         return NULL;
  650.  
  651.     // Get the depth if the image
  652.     depth = pISurround->GetDepth();
  653.  
  654.     // Calculate memory size needed the DIB...
  655.     // ... get the header...
  656.     memSize = sizeof( BITMAPINFOHEADER );
  657.     
  658.     // ...add in the size of the color table
  659.     if( depth == 8 )
  660.         memSize += 256 * sizeof( RGBQUAD );
  661.     
  662.     // ...and the size of the image
  663.     memSize += WIDTHBYTES( depth * pSize->cx ) * pSize->cy;
  664.     
  665.     hMemory = GlobalAlloc( GMEM_MOVEABLE|GMEM_DDESHARE, memSize );
  666.     if( hMemory == NULL )
  667.         return NULL;
  668.     
  669.     pDib = (BITMAPINFOHEADER*)GlobalLock( hMemory );
  670.  
  671.     pDib->biSize = sizeof( BITMAPINFOHEADER );
  672.     pDib->biPlanes = 1;
  673.     pDib->biBitCount = depth;
  674.     pDib->biCompression = BI_RGB;
  675.     pDib->biSizeImage = 0;
  676.     pDib->biClrUsed = 0;
  677.     pDib->biClrImportant = 0;
  678.     pDib->biHeight = pSize->cy;
  679.     pDib->biWidth = pSize->cx;
  680.     FixBitmapInfo(pDib);
  681.  
  682.     pISurround->GetBits( pLocation, pSize, pDib, DibPtr(pDib) );
  683.     if( depth == 8 )
  684.         pISurround->GetColors( 0, 255, DibColors(pDib) );
  685.  
  686.     GlobalUnlock( hMemory );
  687.     
  688.     return hMemory;
  689. }
  690.  
  691. BOOL CSurroundView::PutImage( PDIB pDib, LPSPHERE_POINT pLocation, LPSIZE pSize )
  692. {
  693.     UINT depth;
  694.     ISurround* pISurround = this->GetISurround();
  695.     HRESULT hr;
  696.  
  697.     if( pISurround == NULL )
  698.         return FALSE;
  699.  
  700.     // Get the depth if the image
  701.     depth = pISurround->GetDepth();
  702.  
  703.     if( depth != pDib->biBitCount )
  704.         return FALSE;
  705.     
  706.     hr = pISurround->SetBits( pLocation, pSize, pDib, DibPtr(pDib) );
  707.  
  708.     return FAILED(hr);
  709. }
  710.  
  711. BOOL CSurroundView::CopyImage( LPSPHERE_POINT pLocation, LPSIZE pSize )
  712. {
  713.     
  714.     HGLOBAL hMemory;
  715.  
  716.     if( (hMemory = GetImage( pLocation, pSize )) == NULL )
  717.         return FALSE; 
  718.     
  719.     // Send the DIB to the clipboard
  720.     if( ::OpenClipboard( AfxGetMainWnd()->GetSafeHwnd() ) )
  721.     {
  722.         // we need to get rid of any CF_BITMAPs
  723.         ::EmptyClipboard();
  724.         ::SetClipboardData( CF_DIB, hMemory );
  725.         ::CloseClipboard();
  726.     }
  727.  
  728.     return TRUE;                
  729. }
  730.