home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
msdn_vcb
/
samples
/
vc98
/
atl
/
direct3d
/
d3datl.h
< prev
next >
Wrap
C/C++ Source or Header
|
1998-03-26
|
9KB
|
362 lines
// D3D.h : Declaration of the CDirect3D
//
// 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 <objsafe.h>
#include "resource.h" // main symbols
#include "D3DWnd.h"
//////////////////////////////////////////////////////////////////////////////////////////////////
// CTimer
template <class Derived, class T, const IID* piid>
class CTimer
{
public:
CTimer()
{
m_bTimerOn = FALSE;
}
HRESULT TimerOn(DWORD dwTimerInterval)
{
Derived* pDerived = ((Derived*)this);
m_dwTimerInterval = dwTimerInterval;
if (m_bTimerOn) // already on, just change interval
return S_OK;
m_bTimerOn = TRUE;
m_dwTimerInterval = dwTimerInterval;
m_pStream = NULL;
HRESULT hRes;
hRes = CoMarshalInterThreadInterfaceInStream(*piid, (T*)pDerived, &m_pStream);
// Create thread and pass the thread proc the this ptr
m_hThread = CreateThread(NULL, 0, &_Apartment, (void*)this, 0, &m_dwThreadID);
return S_OK;
}
void TimerOff()
{
if (m_bTimerOn)
{
m_bTimerOn = FALSE;
AtlWaitWithMessageLoop(m_hThread);
}
}
// Implementation
private:
static DWORD WINAPI _Apartment(void* pv)
{
CTimer<Derived, T, piid>* pThis = (CTimer<Derived, T, piid>*) pv;
pThis->Apartment();
return 0;
}
DWORD Apartment()
{
CoInitialize(NULL);
HRESULT hRes;
m_spT.Release();
if (m_pStream)
hRes = CoGetInterfaceAndReleaseStream(m_pStream, *piid, (void**)&m_spT);
while(m_bTimerOn)
{
Sleep(m_dwTimerInterval);
if (!m_bTimerOn)
break;
m_spT->DisplayScene();
}
m_spT.Release();
CoUninitialize();
return 0;
}
// Attributes
public:
DWORD m_dwTimerInterval;
// Implementation
private:
HANDLE m_hThread;
DWORD m_dwThreadID;
LPSTREAM m_pStream;
CComPtr<T> m_spT;
BOOL m_bTimerOn;
};
/////////////////////////////////////////////////////////////////////////////
// CDirect3D
class CDirect3D :
public CComObjectRoot,
public CComCoClass<CDirect3D, &CLSID_CDirect3DCtl>,
public CComControl<CDirect3D>,
public CTimer<CDirect3D, IDirect3DCtl, &IID_IDirect3DCtl>,
public IDispatchImpl<IDirect3DCtl, &IID_IDirect3DCtl, &LIBID_DIRECT3DLib>,
public IPersistStreamInitImpl<CDirect3D>,
public IPersistStorageImpl<CDirect3D>,
public IQuickActivateImpl<CDirect3D>,
public IProvideClassInfo2Impl<&CLSID_CDirect3DCtl, NULL, &LIBID_DIRECT3DLib>,
public IOleControlImpl<CDirect3D>,
public IOleObjectImpl<CDirect3D>,
public IOleInPlaceActiveObjectImpl<CDirect3D>,
public IViewObjectExImpl<CDirect3D>,
public IOleInPlaceObjectWindowlessImpl<CDirect3D>,
public IDataObjectImpl<CDirect3D>,
public IObjectSafetyImpl<CDirect3D, INTERFACESAFE_FOR_UNTRUSTED_CALLER>,
public ISupportErrorInfo
{
public:
CDirect3D()
{
m_hOurWnd = NULL;
m_p3DWindow = NULL;
m_dwSafety = 0;
}
~CDirect3D()
{
// Stop, if we haven't stopped already
if (m_p3DWindow)
Stop3D();
}
DECLARE_REGISTRY_RESOURCEID(IDR_Direct3D)
DECLARE_GET_CONTROLLING_UNKNOWN()
BEGIN_COM_MAP(CDirect3D)
COM_INTERFACE_ENTRY(IDirect3DCtl)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY_IMPL(IViewObjectEx)
COM_INTERFACE_ENTRY_IMPL_IID(IID_IViewObject2, IViewObjectEx)
COM_INTERFACE_ENTRY_IMPL_IID(IID_IViewObject, IViewObjectEx)
COM_INTERFACE_ENTRY_IMPL(IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY_IMPL_IID(IID_IOleInPlaceObject, IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY_IMPL_IID(IID_IOleWindow, IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY_IMPL(IOleInPlaceActiveObject)
COM_INTERFACE_ENTRY_IMPL(IOleControl)
COM_INTERFACE_ENTRY_IMPL(IOleObject)
COM_INTERFACE_ENTRY_IMPL(IQuickActivate)
COM_INTERFACE_ENTRY_IMPL(IPersistStorage)
COM_INTERFACE_ENTRY_IMPL(IPersistStreamInit)
COM_INTERFACE_ENTRY_IMPL(IDataObject)
COM_INTERFACE_ENTRY(IObjectSafety)
COM_INTERFACE_ENTRY(IProvideClassInfo)
COM_INTERFACE_ENTRY(IProvideClassInfo2)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
END_COM_MAP()
BEGIN_MSG_MAP(CDirect3D)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
END_MSG_MAP()
BEGIN_PROPERTY_MAP(CDirect3D)
END_PROPERTY_MAP()
// ISupportsErrorInfo
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
STDMETHOD(OnFrameWindowActivate)(BOOL fActivate)
{
ATLTRACE(_T("OnFrameWindowActivate\n"));
if (fActivate && m_p3DWindow)
m_p3DWindow->SetPalette();
return S_OK;
}
// IDirect3DCtl
public:
// Implementation
public:
// The drawing is done through CDirect3DWindow, so we need
// to do nothing here.
LRESULT OnEraseBackground(UINT, WPARAM, LPARAM, BOOL& bHandled)
{
return 0;
}
LRESULT OnLButtonDown(UINT, WPARAM, LPARAM, BOOL& bHandled)
{
m_p3DWindow->SetPalette();
return 0;
}
HRESULT OnDraw(ATL_DRAWINFO&)
{
// We're not doing any drawing using GDI, so there is nothing to do here.
// We still need to have this function so we don't bring in the default ATL
// drawing code.
return TRUE;
}
HRESULT InPlaceActivate(LONG iVerb, const RECT* prcPosRect = NULL)
{
HRESULT hr;
hr = CComControlBase::InPlaceActivate(iVerb, prcPosRect);
if (!m_p3DWindow) // Start if we haven't started yet
Start3D();
return hr;
}
STDMETHOD(InPlaceDeactivate)(void)
{
if (m_p3DWindow)
Stop3D();
return IOleInPlaceObjectWindowlessImpl<CDirect3D>::InPlaceDeactivate();
}
STDMETHOD(Start3D)()
{
// Find out what window we need to use
GetOurWindow();
// If we haven't got a window yet, then there's nothing we can do
if (m_hOurWnd == NULL)
return E_FAIL;
m_p3DWindow = new CDirect3DWindow;
if (!m_p3DWindow)
{
return E_OUTOFMEMORY;
}
RECT rcInitialPos = m_rcPos;
RectToDesktop(&rcInitialPos);
HRESULT hr = m_p3DWindow->OnCreate(m_hOurWnd, rcInitialPos);
// The OnSize method creates the initial scene
if (SUCCEEDED(hr))
m_p3DWindow->OnSize(m_hOurWnd, m_rcPos.right-m_rcPos.left,
m_rcPos.bottom-m_rcPos.top);
TimerOn(5);
return hr;
}
STDMETHOD(Stop3D)()
{
TimerOff();
delete m_p3DWindow;
m_p3DWindow = NULL;
return S_OK;
}
STDMETHOD(SetObjectRects)(LPCRECT prcPos,LPCRECT prcClip)
{
if (prcPos == NULL)
{
// I've seen VB5 send this
ATLTRACE(_T("WARNING: SetObjects called with NULL prcPos\n"));
return S_OK;
}
HRESULT hr = IOleInPlaceObjectWindowlessImpl<CDirect3D>::SetObjectRects(prcPos, prcClip);
return hr;
}
STDMETHOD(DisplayScene)()
{
if (m_p3DWindow)
{
// m_p3DWindow->SetPalette();
m_p3DWindow->TickScene();
Draw3DWindow();
}
return S_OK;
}
private:
void Draw3DWindow()
{
static RECT rcOldPos;
if (m_p3DWindow)
{
RECT rcPos = m_rcPos;
RectToDesktop(&rcPos);
// Has the size changed
if ((rcPos.right-rcPos.left != rcOldPos.right-rcOldPos.left) ||
(rcPos.bottom-rcPos.top != rcOldPos.bottom-rcOldPos.top))
{
ATLTRACE(_T("Draw(%d,%d,%d,%d)\n"),rcPos.left,rcPos.top,rcPos.right,rcPos.bottom);
m_p3DWindow->OnSize(m_hOurWnd, m_rcPos.right-m_rcPos.left,
m_rcPos.bottom-m_rcPos.top);
ATLTRACE(_T("EndDraw\n"));
}
// Has it moved
if (rcPos.left!=rcOldPos.left || rcPos.top!=rcOldPos.top)
m_p3DWindow->OnMove(m_hOurWnd, rcPos.left, rcPos.top);
rcOldPos = rcPos;
m_p3DWindow->DoFrame();
}
}
// Get the window we need to use. This will either be the window that has already
// been created if we are window. If we are windowless the HWND of the client
// will be retrieved from the HDC.
void GetOurWindow()
{
// If we're windowless we still need an HWND for Direct3d
if (m_bWndLess)
{
HDC hDC;
// Get the HDC from the client
m_spInPlaceSite->GetDC(NULL, OLEDC_NODRAW, &hDC);
m_hOurWnd = WindowFromDC(hDC);
#if 1
// Code to make VB5 paint properly now it has clipped it's own hDC
RECT rect;
::GetClientRect(m_hOurWnd,&rect);
HRGN hRegion = CreateRectRgn(rect.left,rect.top,rect.right,rect.bottom);
SelectClipRgn(hDC,hRegion);
#endif
m_spInPlaceSite->ReleaseDC(hDC);
}
else
m_hOurWnd = m_hWnd;
}
// Convert RECT so that it is relative to the desktop.
void RectToDesktop(RECT* pRect)
{
POINT pt;
pt.x = 0;
pt.y = 0;
::ClientToScreen(m_hOurWnd, &pt);
if (m_bWndLess)
::OffsetRect(pRect, pt.x, pt.y);
else
// If we're not windowless, cater for the fact that pRect will not necessarily be at (0,0)
::OffsetRect(pRect, pt.x-pRect->left, pt.y-pRect->top);
}
HWND m_hOurWnd;
CDirect3DWindow* m_p3DWindow; // Pointer to Direct3D window if we have one
DWORD m_dwSafety; // Current safety settings
};