topical media & game development

talk show tell print

hush-src-multi-DLL-RenderEngine.cpp / cpp



  //------------------------------------------------------------------------------
  // File: RenderEngine.cpp
  //
  // Desc: DirectShow sample code - Implementation of CMultiVMR9RenderEngine
  //
  // Copyright (c) Microsoft Corporation.  All rights reserved.
  //------------------------------------------------------------------------------
  
  include <stdafx.h>
  include <RenderEngine.h>
  include <d3dx9.h>
  
  
****************************Public*Routine******************************\ CMultiVMR9RenderEngine constructor \*************************************************************************

  
  CMultiVMR9RenderEngine::CMultiVMR9RenderEngine(LPUNKNOWN pUnk, HRESULT *phr)
      : CUnknown(NAME("MultiVMR9 Render Engine"), pUnk)
      , m_hwnd( NULL )
      , m_pDevice( NULL)
      , m_pUILayer( NULL )
      , m_pMixerControl( NULL )
      , m_pOwner( NULL )
      , m_bInitialized( FALSE )
      , m_Timer( NULL )
      , m_setFPS( 100000 )
      , m_getFPS( 0 )
      , m_interframe( 33)
      , m_interframeInstant( 0L )
      , m_dwFramesDrawn( 0)
      , m_dwStart(0)
      , m_dwLastRender( 0)
          , m_bChangingDevice( FALSE )
  {
      // make sure timer is at least 2 ms accurate
      timeBeginPeriod(2);
  }
  
  
****************************Public*Routine******************************\ CMultiVMR9RenderEngine destructor \*************************************************************************

  
  CMultiVMR9RenderEngine::~CMultiVMR9RenderEngine()
  {
      HRESULT hr = S_OK;
      CAutoLock Lock(&m_ObjectLock);
  
      // here we have to disconnect child IMultiVMR9UILayer and IMultiVMR9MixerControl
      if( m_pUILayer )
      {
          hr = m_pUILayer->SetRenderEngineOwner( NULL);
          if( FAILED(hr))
          {
              ::DbgMsg("~CMultiVMR9RenderEngine: failed to disconnect child UILayer, he = 0x%08x", hr);
          }
      }
      if( m_pMixerControl )
      {
          hr = m_pMixerControl->SetRenderEngineOwner(NULL);
          if( FAILED(hr))
          {
              ::DbgMsg("~CMultiVMR9RenderEngine: failed to disconnect child mixer control, he = 0x%08x", hr);
          }
      }
      
      Clean_();
      // call off the timer
      timeEndPeriod(2);
  }
  
  
/////////////////// IUnknown
///////////////////////////////////


****************************Public*Routine******************************\ CreateInstance \*************************************************************************

  
  CUnknown* CMultiVMR9RenderEngine::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
  {
      return new CMultiVMR9RenderEngine(pUnk, phr);
  }
  
  
****************************Public*Routine******************************\ NonDelegatingQueryInterface \*************************************************************************

  
  STDMETHODIMP
  CMultiVMR9RenderEngine::NonDelegatingQueryInterface(
      REFIID riid,
      void ** ppv)
  {
      HRESULT hr = E_NOINTERFACE;
      *ppv = NULL;
  
      if (riid == IID_IMultiVMR9RenderEngine) 
      {
          hr = GetInterface((IMultiVMR9RenderEngine *)this, ppv);
      }
      else 
      {
          hr = CUnknown::NonDelegatingQueryInterface(riid,ppv);
      }
      return hr;
  }
  
  
/////////////////// IMultiVMR9RenderEngine
////////////////////////


****************************Public*Routine******************************\ Initialize Call this method right after IMultiVMR9Wizard object is created to configure and initialize internal structures as well as D3D environment. hWnd - handle to valid video window dwFlags - Configuration flags lViewWidth - desired width of the view port. If <=0, render engine will use default backbuffer width lVieweHeight - desired height of the view port. if <=0, render engine will use default value of backbuffer height pMixerControl - customized IMultiVMR9MixerControl, use NULL for the default pUILayer - customized IMultiVMR9UILayer, use NULL if there is no UI layer Return error codes: E_INVALIDARG (invalid config flags or hWnd), VFW_E_WRONG_STATE (method was already called before) E_FAIL (unexpected error), \*************************************************************************

  
  
  STDMETHODIMP CMultiVMR9RenderEngine::Initialize(
      HWND hWnd, 
      DWORD dwFlags,
      IMultiVMR9MixerControl* pMixerControl,
      IMultiVMR9UILayer* pUILayer
      )
  {
      HRESULT hr = S_OK;
  
      if( FALSE == IsWindow( hWnd ))
      {
          ::DbgMsg("CMultiVMR9RenderEngine::Initialize: received invalid window handle");
          return E_INVALIDARG;
      }
  
      if( m_bInitialized )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::Initialize: method was already called");
          return VFW_E_WRONG_STATE;
      }
  
      CAutoLock Lock(&m_ObjectLock);
  
      try
      {
          m_hwnd = hWnd;
  
          // TODO: check flags
          m_dwCfgFlags = dwFlags;
  
          if( pMixerControl )
          {
              m_pMixerControl = pMixerControl;
              m_pMixerControl->AddRef();
  
          }
          else // create default mixer control
          {
              CHECK_HR(
                  hr = CoCreateInstance(  CLSID_MultiVMR9MixerControl, 
                                          NULL, CLSCTX_INPROC_SERVER,
                                          IID_IMultiVMR9MixerControl, 
                                          (void**)&m_pMixerControl),
                  ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed to create default MultiVMR9MixerControl, "\
                      "hr = 0x%08x", hr));
          }
          CHECK_HR(
              m_pMixerControl->SetRenderEngineOwner( this ),
              ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed to advise 'this' owner to the mixer control"));
  
          if( pUILayer )
          {
              m_pUILayer = pUILayer;
              m_pUILayer->AddRef();
              CHECK_HR(
                  m_pUILayer->SetRenderEngineOwner( this ),
                  ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed to advise 'this' owner to the UI layer"));
          }
  
                  hr = CreateDevice_();
  
                  CHECK_HR(
              hr = m_pMixerControl->Initialize( m_pDevice ),
              ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed to initialize mixer control, hr = 0x%08x", hr));
  
          if( m_pUILayer )
          {
              CHECK_HR(
                  hr = m_pUILayer->Initialize( m_pDevice ),
                  ::DbgMsg("CMultiVMR9RenderEngine::Initialize: failed to initialize UI Layer, hr = 0x%08x", hr));
          }
  
          m_bInitialized = TRUE;
      }// try
      catch( HRESULT hr1 )
      {
          hr = hr1;
      }
  
      return hr;
  }
  
  
****************************Public*Routine******************************\ Terminate \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::Terminate( void )
  {
      HRESULT hr = S_OK;
      if( m_pMixerControl )
      {
          hr = m_pMixerControl->SetRenderEngineOwner(NULL);
          if( FAILED(hr))
          {
              ::DbgMsg("CMultiVMR9RenderEngine::Terminate: failed to unadvise RenderEngineOwner for mixer control, hr = 0x%08x", hr);
              return hr;
          }
          RELEASE( m_pMixerControl );
      }
  
      if( m_pUILayer )
      {
          hr = m_pUILayer->SetRenderEngineOwner(NULL);
          if( FAILED(hr))
          {
              ::DbgMsg("CMultiVMR9RenderEngine::Terminate: failed to unadvise RenderEngineOwner for UI layer, hr = 0x%08x", hr);
              return hr;
          }
          RELEASE( m_pUILayer );
      }
      return S_OK;
  }
  
  
****************************Public*Routine******************************\ Render This method is called from a separate thread asynchronously from VMR calls First, method checks internal timer, and if it is time to render new scene, method calls mixer control's methods Compose() and Render(). After that, if UI layer is present, we also call for its Render() method. We also keep track on actual FPS rate here Return error codes: E_INVALIDARG (invalid config flags or hWnd), VFW_E_WRONG_STATE (method was already called before) E_FAIL (unexpected error), \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::Render(void)
  {
      HRESULT hr = S_OK;
      HRESULT hrMC = S_OK;
      HRESULT hrUI = S_OK;
      COLORREF clr = RGB(0,0,0);
      D3DCOLOR backgroundColor;
  
      if( FALSE == m_bInitialized )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::Render: object is not initialized");
          return VFW_E_WRONG_STATE;
      }
  
          if( m_bChangingDevice )
          {
                  hr = ProcessLostDevice();
                  return hr;
          }
  
      DWORD dwCurTime = timeGetTime();
  
      if( 0 == m_dwStart )
      {
          m_dwStart = timeGetTime();
      }
  
      if( dwCurTime - (m_dwStart + m_Timer) < m_interframe )
      {
          return S_OK; // to early to do anything
      }
  
      // time is up: render
      CAutoLock Lock(&m_ObjectLock);
  
      m_interframeInstant = dwCurTime - (m_dwStart + m_Timer);
      
      m_Timer = dwCurTime - m_dwStart;
  
      if( !m_pMixerControl )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::Render: FATAL, cannot find IMultiVMR9MixerControl");
          return E_UNEXPECTED;
      }
  
      hr = m_pMixerControl->GetBackgroundColor( &clr );
  
      if( FAILED(hr))
      {
          backgroundColor = D3DCOLOR_XRGB( 0x00, 0x00, 0x00);
      }
      else
      {
          backgroundColor = D3DCOLOR_XRGB( GetRValue( clr), GetGValue( clr), GetBValue( clr));
      }
  
      try
      {
          hr = m_pMixerControl->Compose( (void*)m_Timer );
          if( FAILED(hr))
          {
              ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in IMultiVMR9MixerControl::Compose, hr = 0x%08x", hr);
              return hr;
          }
                  if( !m_pDevice )
                          throw S_OK;
  
          // render the scene
          CHECK_HR(
              hr = m_pDevice->Clear(  0L,                             // no rects (clear all)
                                      NULL,                           // clear entire viewport
                                      D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,// clear render target
                                      backgroundColor,
                                      1.0f,                           // clear all the depth
                                      0L ),                           // no stencil
              ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in IDirect3DDevice9::Clear, hr = 0x%08x", hr));
  
          CHECK_HR(
              hr = m_pDevice->BeginScene(),
              ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in BeginScene(), hr = 0x%08x",hr));
  
          // first, render all the video source by means of mixer control
          hrMC = m_pMixerControl->Render( m_pDevice, (void*)m_Timer );
  
          if( m_pUILayer )
          {
              hrUI = m_pUILayer->Render( m_pDevice );
          }
          
          CHECK_HR(
              hr = m_pDevice->EndScene(),
              ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in EndScene(), hr = 0x%08x",hr));
  
          CHECK_HR(
              hr = m_pDevice->Present(NULL,NULL,NULL,NULL),
              ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in IDirect3DDevice9::Present(), hr = 0x%08x",hr));
  
          if( FAILED( hrMC ))
          {
              ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in IMultiVMR9MixerControl::Render, error code 0x%08x", hrMC);
              hr = hrMC;
          }
          if( FAILED( hrUI ))
          {
              ::DbgMsg("CMultiVMR9RenderEngine::Render: failed in IMultiVMR9UILayer::Render, error code 0x%08x", hrUI);
              hr = FAILED(hr) ? hrUI : hr;
          }
  
          m_dwFramesDrawn++;
          if( m_dwFramesDrawn == ULONG_MAX ) // we have been running renderer for sooo long
          {
              // flush counters
              m_dwFramesDrawn = 0;
          }
  
          if( m_dwFramesDrawn > 1 )
          {
              m_interframeAvg = m_interframeAvg *(m_dwFramesDrawn-1) + (m_Timer - m_dwLastRender);
              m_interframeAvg /= m_dwFramesDrawn;
          }
          else
          {
              m_interframeAvg = m_interframeInstant;
          }
  
      } // try
      catch( HRESULT hr1 )
      {
                  if( (hr1 == D3DERR_DEVICELOST ||
                           hr1 == D3DERR_DRIVERINTERNALERROR) && m_pOwner )
                  {
                          m_bChangingDevice = TRUE;
                          hr = ProcessLostDevice();
                  }
                  else
                  {
                          hr = hr1;
                  }
      }
      m_dwLastRender = m_Timer;
  
      return hr;
  }
  
  
****************************Public*Routine******************************\ ProcessLostDevice responds to the device loss event \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::ProcessLostDevice()
  {
          HRESULT hr = S_OK;
          // tell all the components that we are lost. so that they would release all the 
          // allocated video resources
          if( m_pMixerControl )
          {
                  hr = m_pMixerControl->BeginDeviceLoss();
          }
          if( m_pUILayer )
          {
                  hr = m_pUILayer->BeginDeviceLoss();
          }
          if( m_pOwner )
          {
                  hr = m_pOwner->BeginDeviceLoss();
          }
          RELEASE( m_pDevice );
          hr = CreateDevice_();
          if( SUCCEEDED(hr) && m_pDevice )
          {
                  if( m_pMixerControl )
                  {
                          hr = m_pMixerControl->EndDeviceLoss( m_pDevice );
                  }
                  if( m_pUILayer )
                  {
                          hr = m_pUILayer->EndDeviceLoss( m_pDevice );
                  }
                  if( m_pOwner )
                  {
                          hr = m_pOwner->EndDeviceLoss( m_pDevice );
                  }
                  m_bChangingDevice = FALSE;
          }
          return hr;
  }
  
  
****************************Public*Routine******************************\ GetUILayer Call this method to obtain pointer to currently used UI layer. if there is no UI Layer involved, method returns *ppUILayer = NULL; Return error codes: E_POINTER (ppUILayer is NULL) VFW_E_WRONG_STATE (method Initialize() was never called) \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::GetUILayer(IMultiVMR9UILayer** ppUILayer)
  {
      HRESULT hr = S_OK;
  
      if( FALSE == m_bInitialized )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetUILayer: object is not initialized");
          return VFW_E_WRONG_STATE;
      }
      if( !ppUILayer )
      {
          return E_POINTER;
      }
      if( m_pUILayer )
      {
          *ppUILayer = m_pUILayer;
          (*ppUILayer)->AddRef();
      }
      else
      {
          *ppUILayer = NULL;
      }
  
      return hr;
  }
  
  
****************************Public*Routine******************************\ SetFrameRate Call this method to specify desired frame rate, in (frames per sec)x100 Render engine will try to keep desired rate, but does not guarantee it, use GetFrameRate() to get actual frame rate Return error codes: E_INVALIDARG (nFramesPerSecBy100 is less than 1 or bigger than 100000) VFW_E_WRONG_STATE (method Initialize() was never called) \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::SetFrameRate(int nFramesPerSecBy100)
  {
      HRESULT hr = S_OK;
      if( FALSE == m_bInitialized )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::SetFrameRate: object is not initialized");
          return VFW_E_WRONG_STATE;
      }
      if( nFramesPerSecBy100 <1 ||
          nFramesPerSecBy100 >100000 )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::SetFrameRate: desired rate must be between 1 and 100000");
          return E_INVALIDARG;
      }
  
      CAutoLock Lock(&m_ObjectLock);
      m_setFPS = nFramesPerSecBy100;
      // update m_interframe which is inverse of FPS
      m_interframe = 100000 / m_setFPS;
  
      // we also have to flush counters for actual FPS
      m_interframeAvg = m_interframe;
  
      return hr;
  }
  
  
****************************Public*Routine******************************\ GetFrameRate Call this method to obtain actual frame rate (instanteneous from the last rendering), in (frames per sec)x100. Once started, renderer stops only when destroyed (and if all the subgraphs are idle, it will be drawing last available images), Return error codes: E_POINTER (pnFramesPerSecBy100 is NULL) VFW_E_WRONG_STATE (method Initialize() was never called) \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::GetFrameRate(int* pnFramesPerSecBy100)
  {
      if( FALSE == m_bInitialized )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetFrameRate: object is not initialized");
          return VFW_E_WRONG_STATE;
      }
      if( !pnFramesPerSecBy100 )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetFrameRate: received NULL pointer");
          return E_POINTER;
      }
      if( m_interframeInstant )
      {
          m_getFPS = 100000L / m_interframeInstant;
      }
      else
      {
          m_getFPS = 0L;
      }
  
      *pnFramesPerSecBy100 = m_getFPS;
      return S_OK;
  }
  
  
****************************Public*Routine******************************\ GetFrameRateAvg Call this method to obtain actual frame rate, smoothed and averaged in time, in (frames per sec)x100. Once started, renderer stops only when destroyed (and if all the subgraphs are idle, it will be drawing last available images), so we calculate actual frame rate as InterFrameTime_ms = (InterFrameTime_ms *(FramesDrawn-1) + (time_from_the_last_rendering_ms)) / FramesDrawn; FrameRateAvg = 100000 / InterFrameTime_ms; Actual calculations are performed in Render(). Return error codes: E_POINTER (pnFramesPerSecBy100 is NULL) VFW_E_WRONG_STATE (method Initialize() was never called) \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::GetFrameRateAvg( int* pnFramesPerSecBy100 )
  {
      if( FALSE == m_bInitialized )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetFrameRateAvg: object is not initialized");
          return VFW_E_WRONG_STATE;
      }
      if( !pnFramesPerSecBy100 )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetFrameRateAvg: received NULL pointer");
          return E_POINTER;
      }
      if( m_interframeAvg )
      {
          *pnFramesPerSecBy100 = 100000L / m_interframeAvg;
      }
      else
      {
          *pnFramesPerSecBy100 = 0L;
      }
      return S_OK;
  }
  
  
****************************Public*Routine******************************\ GetMixingPrefs Call this method to obtain flags with which this render engine was initialized Return error codes: E_POINTER (pdwPrefs is NULL) VFW_E_WRONG_STATE (method Initialize() was never called) \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::GetMixingPrefs(DWORD* pdwPrefs)
  {
      if( FALSE == m_bInitialized )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetMixingPrefs: object is not initialized");
          return VFW_E_WRONG_STATE;
      }
      if( !pdwPrefs )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetMixingPrefs: received NULL pointer");
          return E_POINTER;
      }
  
      *pdwPrefs = m_dwCfgFlags;
      return S_OK;
  }
  
  
****************************Public*Routine******************************\ SetWizardOwner This method is called by IMultiVMR9Wizard when it takes 'this' as a render engine Return error codes: VFW_E_WRONG_STATE (method Initialize() was never called) \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::SetWizardOwner(IMultiVMR9Wizard* pWizard)
  {
      HRESULT hr = S_OK;
      if( FALSE == m_bInitialized )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::SetWizardOwner: object is not initialized");
          return VFW_E_WRONG_STATE;
      }
      CAutoLock Lock(&m_ObjectLock);
  
      RELEASE( m_pOwner );
  
      if( pWizard )
      {
          m_pOwner = pWizard;
          m_pOwner->AddRef();
      }
  
      return hr;
  }
  
  
****************************Public*Routine******************************\ GetWizardOwner Call this method to obtain pointer to IMultiVMR9Wizard that owns 'this' as a render engine Return error codes: E_POINTER ( ppWizard is NULL ) VFW_E_WRONG_STATE (method Initialize() was never called) \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::GetWizardOwner(IMultiVMR9Wizard** ppWizard)
  {
      if( FALSE == m_bInitialized )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetWizardOwner: object is not initialized");
          return VFW_E_WRONG_STATE;
      }
  
      if( !ppWizard )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetWizardOwner: received NULL pointer");
          return E_POINTER;
      }
  
      if( m_pOwner )
      {
          *ppWizard = m_pOwner;
          (*ppWizard)->AddRef();
      }
      else
      {
          *ppWizard = NULL;
      }
      return S_OK;
  }
  
  
****************************Public*Routine******************************\ GetMixerControl Call this method to obtain pointer to IMultiVMR9MixerControl that is used by 'this' render engine. Mixer Control is advised in Initialize() method. Return error codes: E_POINTER ( ppMixerControl is NULL ) VFW_E_WRONG_STATE (method Initialize() was never called) \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::GetMixerControl(IMultiVMR9MixerControl** ppMixerControl)
  {
      if( FALSE == m_bInitialized )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetMixerControl: object is not initialized");
          return VFW_E_WRONG_STATE;
      }
      if( !ppMixerControl )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetMixerControl: received NULL pointer");
          return E_POINTER;
      }
      if( m_pMixerControl )
      {
          *ppMixerControl = m_pMixerControl;
          (*ppMixerControl)->AddRef();
      }
      else
      {
          *ppMixerControl = NULL;
      }
  
      return S_OK;
  }
  
  
****************************Public*Routine******************************\ Get3DDevice Call this method to obtain Direct3DDevice9 used for rendering. This device is created by 'Initialize()' method Return error codes: E_POINTER ( ppDevice is NULL ) VFW_E_WRONG_STATE (method Initialize() was never called) \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::Get3DDevice(IDirect3DDevice9 ** ppDevice)
  {
      if( FALSE == m_bInitialized )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::Get3DDevice: object is not initialized");
          return VFW_E_WRONG_STATE;
      }
      if( !ppDevice )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::Get3DDevice: received NULL pointer");
          return E_POINTER;
      }
      if( m_pDevice )
      {
          *ppDevice = m_pDevice;
          (*ppDevice)->AddRef();
      }
      else
      {
          *ppDevice = NULL;
      }
  
      return S_OK;
  }
  
  
****************************Public*Routine******************************\ GetVideoWindow Call this method to obtain handle to the video window. This handle is sent to 'Initialize()' method Return error codes: E_POINTER ( phwnd is NULL ) VFW_E_WRONG_STATE (method Initialize() was never called) \*************************************************************************

  
  STDMETHODIMP CMultiVMR9RenderEngine::GetVideoWindow(HWND *phwnd)
  {
      if( FALSE == m_bInitialized )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetVideoWindow: object is not initialized");
          return VFW_E_WRONG_STATE;
      }
      if( !phwnd )
      {
          ::DbgMsg("CMultiVMR9RenderEngine::GetVideoWindow: received NULL pointer");
          return E_POINTER;
      }
  
      *phwnd = m_hwnd;
      return S_OK;
  }
  
  
///////////////// Private routine
/////////////////////////////////


****************************Private*Routine******************************\ CreateDevice_ creates IDirect3DDevice9 \*************************************************************************

  
  HRESULT CMultiVMR9RenderEngine::CreateDevice_()
  {
          HRESULT hr = S_OK;
  
      D3DPRESENT_PARAMETERS pp;
      IDirect3D9*     pD3D9 = NULL;
  
          try
          {
                  // create Direct3D
                  pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
  
          CHECK_HR( 
              pD3D9 ? S_OK : E_FAIL,
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed to create Direct3D9 object"));
  
          // create device
          D3DFORMAT D3DFormatAlternatives[] = 
                      {
                          D3DFMT_X8R8G8B8,
                          D3DFMT_R5G6B5,
                          D3DFMT_A8B8G8R8,
                          D3DFMT_X4R4G4B4,
                          D3DFMT_A4R4G4B4,
                          D3DFMT_A1R5G5B5,
                          D3DFMT_X1R5G5B5,
                      };
  
          int nD3DFormatAlternatives = sizeof(D3DFormatAlternatives) / sizeof(D3DFORMAT);
  
          // try different alternatives
          for( int nFmt = 0; nFmt < nD3DFormatAlternatives; nFmt++)
          {
              D3DFORMAT fmt = D3DFormatAlternatives[ nFmt ];
  
              ZeroMemory( &pp, sizeof(D3DPRESENT_PARAMETERS));
              pp.Windowed = TRUE;
              pp.hDeviceWindow = m_hwnd;
              pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
              pp.BackBufferCount = 1;
              pp.BackBufferFormat = fmt;
              pp.EnableAutoDepthStencil = TRUE;
              pp.AutoDepthStencilFormat = D3DFMT_D16;
              pp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
              pp.PresentationInterval = 0x80000000;
  
              
              hr = pD3D9->CreateDevice(D3DADAPTER_DEFAULT ,
                                      D3DDEVTYPE_HAL,
                                      m_hwnd,
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED,
                                      &pp,
                                      &m_pDevice);
              if( SUCCEEDED(hr) && m_pDevice )
                  break;
          }// for
  
          hr = m_pDevice ? S_OK : hr;
          CHECK_HR(
              hr,
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed to create device, error code 0x%08x", hr));
  
          //maximum ambient light
          CHECK_HR(
              m_pDevice->SetRenderState(D3DRS_AMBIENT,RGB(255,255,255)),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetRenderState(D3DRS_AMBIENT...)"));
  
          //lighting disabled
          CHECK_HR(
              m_pDevice->SetRenderState(D3DRS_LIGHTING,FALSE),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetRenderState(D3DRS_LIGHTING...)"));
  
          //don't cull backside
          CHECK_HR(
              m_pDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetRenderState(D3DRS_CULLMODE...)"));
  
          //DISABLE depth buffering
          CHECK_HR(
              m_pDevice->SetRenderState(D3DRS_ZENABLE,D3DZB_FALSE),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetRenderState(D3DRS_ZENABLE...)"));
  
          // enable dithering
          CHECK_HR(
              m_pDevice->SetRenderState(D3DRS_DITHERENABLE, TRUE),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetRenderState(D3DRS_DITHERENABLE...)"));
  
          // disable stensil
          CHECK_HR(
              m_pDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetRenderState(D3DRS_STENCILENABLE...)"));
  
          // manage blending
          CHECK_HR(
              m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetRenderState(D3DRS_ALPHABLENDENABLE...)"));
  
          CHECK_HR(
              m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetRenderState(D3DRS_SRCBLEND...)"));
  
          CHECK_HR(
              m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetRenderState(D3DRS_DESTBLEND...)"));
  
          CHECK_HR(
              m_pDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetRenderState(D3DRS_ALPHATESTENABLE...)"));
  
          CHECK_HR(
              m_pDevice->SetRenderState(D3DRS_ALPHAREF, 0x10),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetRenderState(D3DRS_ALPHAREF...)"));
  
          CHECK_HR(
              m_pDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetRenderState(D3DRS_ALPHAFUNC...)"));
  
          // set up sampler
  
          CHECK_HR(
              m_pDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU,  D3DTADDRESS_CLAMP),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetSamplerState(D3DSAMP_ADDRESSU...)"));
  
          CHECK_HR(
              m_pDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV,  D3DTADDRESS_CLAMP),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetSamplerState(D3DSAMP_ADDRESSV...)"));
  
          CHECK_HR(
              m_pDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetSamplerState(D3DSAMP_MAGFILTER...)"));
  
          CHECK_HR(
              m_pDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR),
              ::DbgMsg("CMultiVMR9RenderEngine::CreateDevice_: failed in SetSamplerState(D3DSAMP_MINFILTER...)"));
  
          }// try
          catch( HRESULT hr1 )
          {
                  hr = hr1;
          }
  
      RELEASE( pD3D9 );
          return hr;
  }
  
  
****************************Private*Routine******************************\ Clean_ clean all the data, release all interfaces \*************************************************************************

  
  void CMultiVMR9RenderEngine::Clean_()
  {
      if( m_pOwner ) { m_pOwner->Release(); m_pOwner = NULL; }
      if( m_pMixerControl ) { m_pMixerControl->Release(); m_pMixerControl = NULL; }
      if( m_pUILayer ){ m_pUILayer->Release(); m_pUILayer = NULL; }
      if( m_pDevice ){ m_pDevice->Release(); m_pDevice = NULL; }
  //    if( m_pRenderTarget ){ m_pRenderTarget->Release(); m_pRenderTarget = NULL;}
  }
  
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.