home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / atl / atltangram / atlgdiworld / atltangramgdivisual.cpp < prev    next >
C/C++ Source or Header  |  1998-03-26  |  8KB  |  323 lines

  1. // AtlTangramGdiVisual.cpp : Implementation of CAtlTangramGdiVisual
  2. //
  3. // This is a part of the Active Template Library.
  4. // Copyright (C) 1996-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Active Template Library Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Active Template Library product.
  12.  
  13. #include "stdafx.h"
  14. #include "ATLGdiWorld.h"
  15. #include "AtlTangramGdiVisual.h"
  16. #include "ATLModel.h"
  17.  
  18.  
  19. /////////////////////////////////////////////////////////////////////////////
  20. // CAtlTangramGdiVisual
  21.  
  22. ///////////////////////////////////////////////////////////
  23. //
  24. // Destructor
  25. //
  26. CAtlTangramGdiVisual::~CAtlTangramGdiVisual()
  27. {
  28.  
  29.     // We keep a strong reference to the model.
  30.     // Therefore, we need to release it here.
  31.     m_pModel->Release() ;
  32.     m_pModel = NULL ;
  33.  
  34.     // We maintain a weak reference to GdiWorld to avoid
  35.     // reference cycles. A weak reference means that we
  36.     // do not AddRef or Release the pointer.
  37.     //m_pGdiWorld->Release() ;
  38.     //m_pGdiWorld = NULL ;
  39.  
  40.  
  41.     // Delete the vertex array.
  42.     if (m_ptVertices != NULL)
  43.     {
  44.         delete [] m_ptVertices ;
  45.     }
  46.  
  47. }
  48.  
  49. ///////////////////////////////////////////////////////////
  50. //
  51. //                      IAtlTangramGdiVisual
  52. //
  53. ///////////////////////////////////////////////////////////
  54. //
  55. // IAtlTangramGdiVisual::Initialize Implementation
  56. //
  57. HRESULT CAtlTangramGdiVisual::Initialize(IATLTangramModel* pModel, IAtlTangramGdiWorld* pWorld)
  58. {
  59.     if (!IsValidInterface(pModel) || !IsValidInterface(pWorld))
  60.     {
  61.         ASSERT(0) ;
  62.         return E_POINTER ;
  63.     }
  64.  
  65.     if (m_pModel != NULL || m_pGdiWorld != NULL)
  66.     {
  67.         // Cannot re-initialize.
  68.         ASSERT(0) ;
  69.         return E_FAIL ;
  70.     }
  71.  
  72.     // Keep a strong reference to the model.
  73.     m_pModel = pModel ;
  74.     m_pModel->AddRef() ;
  75.  
  76.     // To avoid a cyclical reference count, we have a weak reference to GdiWorld.
  77.     // Therefore, we do not AddRef this pointer.
  78.     m_pGdiWorld = pWorld ;
  79.  
  80.     // Get the number of vertices in the model.
  81.     HRESULT hr = m_pModel->GetNumberOfVertices(&m_cVertices) ;
  82.     ASSERT_HRESULT(hr) ;
  83.  
  84.     // Create an array to hold the vertices.
  85.     m_ptVertices = new POINT[m_cVertices] ;
  86.  
  87.     //  ----- Set up event sync -----
  88.     return  AdviseConnectionPoint(pModel);
  89. }
  90.  
  91. ///////////////////////////////////////////////////////////
  92. //
  93. // IAtlTangramGdiVisual::DrawOn Implementation
  94. //
  95. HRESULT CAtlTangramGdiVisual::DrawOn(IAtlTangramCanvas* pCanvas)
  96. {
  97.     // Preconditions.
  98.     if (!IsValidInterface(pCanvas))
  99.     {
  100.         ASSERT(0) ;
  101.         return E_POINTER ;
  102.     }
  103.  
  104.     // Get a device context to draw on from the canvas.
  105.     HDC hDC ;
  106.     HRESULT hr = pCanvas->GetHDC(&hDC) ;
  107.     ASSERT_HRESULT(hr) ;
  108.  
  109.     // Make a pen.
  110.     HPEN hPen = ::CreatePen(PS_SOLID, 1, m_bSelected ? RGB(255,0,0) : RGB(128,128,128)) ;
  111.     HPEN hOldPen = (HPEN) ::SelectObject(hDC, hPen) ;
  112.  
  113.     // Make a brush.
  114.     HBRUSH hOldBrush = (HBRUSH)::SelectObject(hDC, ::GetStockObject(m_bSelected ? NULL_BRUSH : LTGRAY_BRUSH)) ;
  115.  
  116.     // Draw the polygon.
  117.     ::Polygon(hDC, m_ptVertices, m_cVertices) ;
  118.  
  119.     // CleanUp
  120.     ::SelectObject(hDC, hOldPen) ;
  121.     ::SelectObject(hDC, hOldBrush) ;
  122.  
  123.     ::DeleteObject(hPen) ;
  124.  
  125.     return S_OK ;
  126. }
  127.  
  128.  
  129. ///////////////////////////////////////////////////////////
  130. //
  131. // IAtlTangramGdiVisual::IsPtIn Implementation
  132. //
  133. HRESULT CAtlTangramGdiVisual::IsPtIn(POINT pt)
  134. {
  135.     ASSERT( m_ptVertices != NULL) ;
  136.     ASSERT( m_cVertices != 0) ;
  137.  
  138.     // Create a region.
  139.     HRGN hrgnPolygon = ::CreatePolygonRgn(m_ptVertices, m_cVertices, ALTERNATE) ;
  140.  
  141.     // Is point in region?
  142.     BOOL bResult = ::PtInRegion(hrgnPolygon, pt.x, pt.y) ;
  143.  
  144.     // Cleanup
  145.     ::DeleteObject(hrgnPolygon) ;
  146.  
  147.     // Return the results.
  148.     return (bResult) ? S_OK : S_FALSE ;
  149. }
  150.  
  151. ///////////////////////////////////////////////////////////
  152. //
  153. // IAtlTangramGdiVisual::GetBoundingRect
  154. //
  155. // Results:
  156. //          S_FALSE -   If the boundary doesn't make sense.
  157. //
  158. HRESULT CAtlTangramGdiVisual::GetBoundingRect(RECT* pBoundingRect)
  159. {
  160.     if (!IsValidAddress(pBoundingRect, sizeof(RECT), TRUE))
  161.     {
  162.         ASSERT(0) ;
  163.         return E_POINTER ;
  164.     }
  165.  
  166.     HRESULT hr = S_OK ;
  167.     // Create a region.
  168.     HRGN hrgnPolygon = ::CreatePolygonRgn(m_ptVertices, m_cVertices, ALTERNATE) ;
  169.  
  170.     // Get the bounding box for the region.
  171.     RECT rect ;
  172.     int bRgnType = ::GetRgnBox(hrgnPolygon, &rect) ;
  173.     if (bRgnType == NULLREGION || bRgnType == ERROR)
  174.     {
  175.         ::SetRectEmpty(pBoundingRect) ;
  176.         hr = S_FALSE ;
  177.     }
  178.     else
  179.     {
  180.         // Add room for the pen width boundary.
  181.         pBoundingRect->top    = rect.top    - 2 ;
  182.         pBoundingRect->bottom = rect.bottom + 2 ;
  183.         pBoundingRect->left   = rect.left   - 2 ;
  184.         pBoundingRect->right  = rect.right  + 2 ;
  185.     }
  186.  
  187.     // Cleanup
  188.     ::DeleteObject(hrgnPolygon) ;
  189.  
  190.     return hr ;
  191. }
  192.  
  193. ///////////////////////////////////////////////////////////
  194. //
  195. //                      ITangramVisual
  196. //
  197. ///////////////////////////////////////////////////////////
  198. //
  199. // ITangramVisual::SetSelected Implementation.
  200. //
  201. HRESULT CAtlTangramGdiVisual::SetSelected(BOOL bSelected)
  202. {
  203.     m_bSelected = bSelected ;
  204.  
  205.     // Add the boundary to the update region.
  206.     RECT rectBounding;
  207.     GetBoundingRect(&rectBounding) ;
  208.     HRESULT hr = m_pGdiWorld->AddUpdateRect(rectBounding) ;
  209.     ASSERT_HRESULT(hr) ;
  210.  
  211.     hr = m_pGdiWorld->Animate() ;
  212.     ASSERT_HRESULT(hr) ;
  213.  
  214.     return S_OK ;
  215. }
  216.  
  217. ///////////////////////////////////////////////////////////
  218. //
  219. // IAtlTangramGdiVisual::GetModel Implementation
  220. //
  221. HRESULT CAtlTangramGdiVisual::GetModel(const IID& iid, IUnknown** ppI)
  222. {
  223.     if (!IsValidInterfaceOutParam(ppI))
  224.     {
  225.         ASSERT(0) ;
  226.         return E_POINTER ;
  227.     }
  228.  
  229.    return m_pModel->QueryInterface(iid, (void**)ppI)  ;
  230. }
  231.  
  232. ///////////////////////////////////////////////////////////
  233. //
  234. //                  ITangramModelEvent
  235. //
  236. ///////////////////////////////////////////////////////////
  237. //
  238. // ITangramModelEvent::OnModelChange
  239. //
  240. HRESULT __stdcall CAtlTangramGdiVisual::OnModelChange()
  241. {
  242.     // Get Current Bounding Rectangle
  243.     RECT rectBounding;
  244.     GetBoundingRect(&rectBounding) ;
  245.     HRESULT hr = m_pGdiWorld->AddUpdateRect(rectBounding) ;
  246.     ASSERT_HRESULT(hr) ;
  247.  
  248.     // Get the new vertices.
  249.     SyncToModel() ;
  250.  
  251.     // Get New Bounding Rectangle
  252.     GetBoundingRect(&rectBounding) ;
  253.     hr = m_pGdiWorld->AddUpdateRect(rectBounding) ;
  254.     ASSERT_HRESULT(hr) ;
  255.  
  256.     hr = m_pGdiWorld->Animate() ;
  257.     ASSERT_HRESULT(hr) ;
  258.  
  259.     return S_OK ;
  260. }
  261.  
  262. ///////////////////////////////////////////////////////////
  263. //
  264. //                  Helper Functions
  265. //
  266. ///////////////////////////////////////////////////////////
  267. //
  268. //
  269. //
  270. void CAtlTangramGdiVisual::SyncToModel()
  271. {
  272.     // Create an array to hold the new vertices.
  273.     TangramPoint2d* pointds = new TangramPoint2d[m_cVertices] ;
  274.  
  275.     // Get the vertices from the model.
  276.     HRESULT hr = m_pModel->GetVertices(m_cVertices, pointds) ;
  277.     ASSERT_HRESULT(hr) ;
  278.  
  279.     // Convert the vertices to our coordinates.
  280.     for (int i = 0 ; i < m_cVertices ; i++)
  281.     {
  282.         hr = m_pGdiWorld->ModelToDevice(pointds[i], &m_ptVertices[i]) ;
  283.         ASSERT_HRESULT(hr) ;
  284.     }
  285.  
  286.     // Cleanup.
  287.     delete [] pointds;
  288. }
  289.  
  290. STDMETHODIMP CAtlTangramGdiVisual::ReleaseConnectionPoint()
  291. {
  292.     HRESULT hr = S_OK;
  293.     // Release the event source component.
  294.     if (m_pIConnectionPoint != NULL)
  295.     {
  296.         // We no longer need to be enformed of events
  297.         hr = m_pIConnectionPoint->Unadvise(m_dwCookie) ;
  298.         ASSERT_HRESULT(hr) ;
  299.  
  300.         m_pIConnectionPoint->Release() ;
  301.     }
  302.     return hr;
  303. }
  304.  
  305. HRESULT __stdcall CAtlTangramGdiVisual::AdviseConnectionPoint(IATLTangramModel* pModel)
  306. {
  307.     // Get the connection point container from the model.
  308.     IConnectionPointContainer* pContainer = NULL ;
  309.     HRESULT hr = pModel->QueryInterface(IID_IConnectionPointContainer, (void**)&pContainer) ;
  310.     if(!SUCCEEDED(hr))
  311.         return hr;
  312.  
  313.     // Get our desired connection point. Cache the pointer so we can
  314.     // UnAdvise() the connection point when we're done sinking on it
  315.     hr = pContainer->FindConnectionPoint(IID_IATLTangramModelEvent, &m_pIConnectionPoint) ;
  316.     pContainer->Release() ;
  317.     if(!SUCCEEDED(hr))
  318.         return hr;
  319.  
  320.     // Advise the model that we are sinking its event source
  321.     return m_pIConnectionPoint->Advise(GetUnknown(), &m_dwCookie) ;
  322. }
  323.