// AtlTangramGLVisual.cpp : Implementation of CAtlTangramGLVisual // // This is a part of the Active Template Library. // Copyright (C) 1996-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Active Template Library Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Active Template Library product. #include "stdafx.h" #include "GLWorld.h" #include "TanGLVis.h" #include "event_i_i.c" #include #include // STL Interfaces #include #include #include #include #include "util.h" #include "util.cpp" #include "CGL.h" #include "CGL.cpp" #include "CGL-Pal.cpp" // Interfaces #include "TanCanv_i.c" #include "AtlModel.h" #include "GdiWorld.h" #include "GdiWorld_i.c" // Sub-Components. #include "AtlModel_i.c" // Other #include #include #include /////////////////////////////////////////////////////////// // // Destructor // CAtlTangramGLVisual::~CAtlTangramGLVisual() { // We keep a strong reference to the model. // Therefore, we need to release it here. m_pModel->Release(); m_pModel = NULL; // We maintain a weak reference to GdiWorld to avoid // reference cycles. A weak reference means that we // do not need to Release m_pGdiWorld here. // Delete the vertex array. delete [] m_ptVertices; } /////////////////////////////////////////////////////////// // ITangramVisual // ITangramVisual::SetSelected Implementation. HRESULT CAtlTangramGLVisual::SetSelected(BOOL bSelected) { m_bSelected = bSelected; // Update the display. HRESULT hr = m_pWorld->Animate(); ASSERT_HRESULT(hr); return S_OK; } /////////////////////////////////////////////////////////// // ITangramGLVisual::GetModel Implementation HRESULT CAtlTangramGLVisual::GetModel(const IID& iid, IUnknown** ppI) { if (!IsValidInterfaceOutParam(ppI)) { ASSERT(0); return E_POINTER; } return m_pModel->QueryInterface(iid, (void**)ppI) ; } /////////////////////////////////////////////////////////// // ITangramGLVisual // ITangramGLVisual::Initialize Implementation HRESULT __stdcall CAtlTangramGLVisual::Initialize(IATLTangramModel* pModel, IAtlTangramGLWorld* pWorld) { if (!IsValidInterface(pModel)|| !IsValidInterface(pWorld)) { ASSERT(0); return E_POINTER; } if (m_pModel != NULL || m_pWorld != NULL) { // Cannot re-initialize. ASSERT(0); return E_FAIL; } // Keep a strong reference to the model. m_pModel = pModel; m_pModel->AddRef(); // To avoid a cyclical reference count, we have a // weak reference to GLWorld. Therefore, we do // not AddRef this pointer. m_pWorld = pWorld; // Get the number of vertices in the model. HRESULT hr = m_pModel->GetNumberOfVertices(&m_cVertices); ASSERT_HRESULT(hr); // Create an array to hold the vertices. m_ptVertices = new TangramPoint2d[m_cVertices]; // Set up event sync // Create a sink object. TCHAR buf[128]; wsprintf(buf, _T("Visual: m_dwRef = %d\n"), m_dwRef); ATLTRACE(buf); // Get the connection point container. IConnectionPointContainer* pContainer = NULL; hr = pModel->QueryInterface(IID_IConnectionPointContainer, (void**)&pContainer); ASSERT_HRESULT(hr); // Get our desired connection point. Cache the pointer so // we don't have to get it again. hr = pContainer->FindConnectionPoint(IID_IATLTangramModelEvent, &m_pIConnectionPoint); pContainer->Release(); ASSERT_HRESULT(hr); IATLTangramModelEvent* pIATLTangramModelEvent; hr = GetUnknown()->QueryInterface(IID_IATLTangramModelEvent, (void**)&pIATLTangramModelEvent); wsprintf(buf, _T("Visual: m_dwRef = %d\n"), m_dwRef); ATLTRACE(buf); // Ask the visual to advise us of any changes. hr = m_pIConnectionPoint->Advise(pIATLTangramModelEvent, &m_dwCookie); ASSERT_HRESULT(hr); wsprintf(buf, _T("Visual: m_dwRef = %d\n"), m_dwRef); ATLTRACE(buf); // We don't need to keep a reference to the sink. pIATLTangramModelEvent->Release(); wsprintf(buf, _T("Visual: m_dwRef = %d\n"), m_dwRef); ATLTRACE(buf); return S_OK; } /////////////////////////////////////////////////////////// // ITangramGLVisual::DrawOn Implementation HRESULT CAtlTangramGLVisual::DrawOn(IAtlTangramCanvas* pCanvas) { // Preconditions. if (!m_bFirstEvent) { // We have not received a model change event to initialize use. return S_FALSE; } if (!IsValidInterface(pCanvas)) { ASSERT(0); return E_POINTER; } double thickness = 0.01; if (m_bSelected) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Bottom glNormal3d(0.0, 0.0, -1.0); glBegin(GL_TRIANGLE_FAN); for (int i = 0; i < m_cVertices; i++) glVertex2d(m_ptVertices[i].x, m_ptVertices[i].y); glEnd(); // Top glNormal3d(0.0, 0.0, 1.0); glBegin(GL_TRIANGLE_FAN); for (i = 0; i < m_cVertices; i++) glVertex3d(m_ptVertices[i].x, m_ptVertices[i].y, thickness); glEnd(); // Sides for (i = 0; i < m_cVertices; i++) { int iNextIndex = (i+1) % m_cVertices; // Compute Normal [v1 - v2] X [v2 - v3] see page 58 of RedBook // V1 = v1 - v2 double X1 = m_ptVertices[i].x - m_ptVertices[iNextIndex].x; double Y1 = m_ptVertices[i].y - m_ptVertices[iNextIndex].y; double Z1 = 0.0; // 0.0f - 0.0f; // V2 = v2 - v3 double X2 = 0.0; //m_ptVertices[iNextIndex].x - m_ptVertices[iNextIndex].x; double Y2 = 0.0; //m_ptVertices[iNextIndex].y - m_ptVertices[iNextIndex].y; double Z2 = -thickness; // 0.0 - thickness; // V = V1 X V2 double X = Y1 * Z2; //Y1*Z2 - Z1*Y2 = Y1*Z2 - 0.0*0.0; double Y = -X1 * Z2; //Z1*X2 - X1*Z2 = 0.0*0.0 - X1*Z2 //double Z = 0.0; //X1*Y2 - Y1*X2; // Normalize double d = sqrt(X*X + Y*Y /*+ Z*Z*/); ASSERT( d != 0.0); X /= d; Y /= d; //Z /= d; glNormal3d(X, Y, 0.0/*Z*/); glBegin(GL_QUADS); glVertex3d(m_ptVertices[i].x, m_ptVertices[i].y, 0.0); glVertex3d(m_ptVertices[iNextIndex].x, m_ptVertices[iNextIndex].y, 0.0); glVertex3d(m_ptVertices[iNextIndex].x, m_ptVertices[iNextIndex].y, thickness); glVertex3d(m_ptVertices[i].x, m_ptVertices[i].y, thickness); glEnd(); } if (m_bSelected) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); return S_OK; } /////////////////////////////////////////////////////////// // ITangramModelEvent // ITangramModelEvent::OnModelChange HRESULT __stdcall CAtlTangramGLVisual::OnModelChange() { // Create an array to hold the new vertices. TangramPoint2d* pointds = new TangramPoint2d[m_cVertices]; // Get the vertices from the model. HRESULT hr = m_pModel->GetVertices(m_cVertices, pointds); ASSERT_HRESULT(hr); // Convert the vertices to our coordinates. for (int i = 0; i < m_cVertices; i++) { hr = m_pWorld->ModelToDevice(pointds[i], &m_ptVertices[i]); ASSERT_HRESULT(hr); } // Cleanup; delete [] pointds; // We are in sync. m_bFirstEvent = TRUE; // Update the display. hr = m_pWorld->Animate(); ASSERT_HRESULT(hr); return S_OK; } STDMETHODIMP CAtlTangramGLVisual::ReleaseConnectionPoint() { HRESULT hr = S_OK; // Release the event source component. if (m_pIConnectionPoint != NULL) { // We no longer need to be enformed of events HRESULT hr = m_pIConnectionPoint->Unadvise(m_dwCookie); ASSERT_HRESULT(hr); m_pIConnectionPoint->Release(); } return hr; }