home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Utilities / Content Creation Tool Plug-Ins / Maya / Sources / Viewer.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  31.3 KB  |  1,065 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: Viewer.cpp
  3. //
  4. // Creates a window for viewing a standard semantics and annotations mesh 
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #include "PreviewPipeline.h"
  10. #include "XExporter.h"
  11. #include "viewer.h"
  12. #include "windowsx.h"
  13.  
  14.  
  15. #include <process.h>
  16.  
  17.  
  18. #include<maya/MDagPath.h>
  19. #include<maya/M3dView.h>
  20. #include<maya/MFnCamera.h>
  21. #include<maya/MFloatMatrix.h>
  22. #include<maya/MMatrix.h>
  23. #include <maya/MFnCamera.h>
  24. #include <maya/MPoint.h>
  25. #include <maya/MVector.h>
  26.  
  27.  
  28. CGrowableArray< CViewer* >& CViewer::GetViewerList()
  29. {
  30.     // Using an accessor function gives control of the construction order
  31.     static CGrowableArray< CViewer* > ViewerList;
  32.     return ViewerList;
  33. }
  34.  
  35.  
  36. //-------------------------------------------------------------------------------------
  37. UINT __stdcall CViewer::StaticRunThread( void* pParam )
  38. {
  39.     CViewer* pViewer = (CViewer*) pParam;
  40.     return pViewer->RunThread();
  41. }
  42.  
  43.  
  44. //-------------------------------------------------------------------------------------
  45. LRESULT CALLBACK CViewer::StaticMsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  46. {
  47.     // Loop through all known viewers and see if this message is intended for the owned
  48.     // window
  49.     CGrowableArray< CViewer* >& Viewers = GetViewerList();
  50.  
  51.     for( int i=0; 
  52.         i < Viewers.GetSize(); 
  53.         i++ )
  54.     {
  55.         CViewer* pViewer = Viewers[ i ];
  56.  
  57.         if( pViewer->GetRenderWindow() == hWnd )
  58.             return pViewer->MsgProc( hWnd, uMsg, wParam, lParam );
  59.     }
  60.  
  61.     return DefWindowProc( hWnd, uMsg, wParam, lParam );
  62. }
  63.  
  64.  
  65.  
  66.  
  67.  
  68. //-------------------------------------------------------------------------------------
  69. CViewer::CViewer()
  70. {
  71.     // Add this instance to the global list
  72.     GetViewerList().Add( this );
  73.  
  74.     // TODO: flush this out
  75.     m_pFont = NULL;
  76.     m_pTextSprite = NULL;
  77.     m_bCreated = false;
  78.     m_bVisible = false;
  79.     m_hWndBound = NULL;
  80.  
  81.     m_dwWidth = 0;
  82.     m_dwHeight = 0;
  83. }
  84.  
  85.  
  86. //-------------------------------------------------------------------------------------
  87. CViewer::~CViewer()
  88. {
  89.     // Remove this instance from the global list
  90.     GetViewerList().Remove( GetViewerList().IndexOf( this ) );
  91. }
  92.  
  93.  
  94. //-------------------------------------------------------------------------------------
  95. UINT __stdcall CViewer::RunThread()
  96. {
  97.     EnterCriticalSection(&DeviceAndViewerSection);
  98.     HRESULT hr= S_OK;
  99.  
  100.     // Register the window class
  101.     WNDCLASS wndClass;
  102.     wndClass.style = CS_DBLCLKS;
  103.     wndClass.lpfnWndProc = StaticMsgProc;
  104.     wndClass.cbClsExtra = 0;
  105.     wndClass.cbWndExtra = 0;
  106.     wndClass.hInstance = m_CreateArgs.hInstance;
  107.     wndClass.hIcon = m_CreateArgs.hIcon;
  108.     wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
  109.     wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  110.     wndClass.lpszMenuName = NULL;
  111.     wndClass.lpszClassName = L"Direct3DWindowClass";
  112.  
  113.     if( !RegisterClass( &wndClass ) )
  114.     {
  115.         DWORD dwError = GetLastError();
  116.         if( dwError != ERROR_CLASS_ALREADY_EXISTS )
  117.             return HRESULT_FROM_WIN32(dwError);
  118.     }
  119.  
  120.     // Set the window's initial style.  It is invisible initially since it might
  121.     // be resized later
  122.     DWORD dwWindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | 
  123.                             WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
  124.     
  125.     // Create the render window
  126.     m_hWndShell = (HWND) M3dView::applicationShell();
  127.     m_hWnd = CreateWindow( L"Direct3DWindowClass", m_CreateArgs.strWindowTitle, dwWindowStyle,
  128.                             m_CreateArgs.x, m_CreateArgs.y, m_CreateArgs.width, m_CreateArgs.height, NULL,
  129.                             m_CreateArgs.hMenu, m_CreateArgs.hInstance, 0 );
  130.     if( m_hWnd == NULL )
  131.     {
  132.         DWORD dwError = GetLastError();
  133.         return HRESULT_FROM_WIN32( dwError );
  134.     }
  135.  
  136.     SetParent(m_hWnd, m_hWndShell);
  137.  
  138.     Hide();
  139.     BindToWindow( NULL, false );
  140.  
  141.     // Start a timer to check for resize
  142.     SetTimer( m_hWnd, 0xffff, 200, NULL );
  143.         
  144.     LeaveCriticalSection(&DeviceAndViewerSection);
  145.  
  146.     // Now that the window has been created start the message loop
  147.     bool bGotMsg;
  148.     MSG  msg;
  149.     msg.message = WM_NULL;
  150.     //prime for WM_QUIT on first loop
  151.  
  152.     for(msg.message = WM_NULL;
  153.         WM_QUIT != msg.message;
  154.         Sleep( 60 ))
  155.     {
  156.  
  157.         if(m_bDestroyCalled == true)
  158.         {
  159.             m_bDestroyCalled = false;
  160.             SetParent(m_hWnd, NULL);
  161.             DestroyWindow(m_hWnd);
  162.             PostQuitMessage(0);
  163.         }
  164.  
  165.  
  166.  
  167.         // Use PeekMessage() so we can use idle time to render the scene. 
  168.         if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) 
  169.         && (WM_QUIT != msg.message))
  170.         {
  171.             // Translate and dispatch the message
  172.             TranslateMessage( &msg );
  173.             DispatchMessage( &msg );
  174.         }
  175.         else if(WM_QUIT != msg.message)
  176.         {
  177.             CPipelineLock Lock;
  178.               if(m_pPreviewPipeline->SceneReadLock(false, Lock))
  179.             {
  180.                 // Render a frame during idle time (no messages are waiting)
  181.                 if( m_nPauseCount == 0 )
  182.                 {
  183.                     m_fTime = (float) DXUTGetGlobalTimer()->GetAbsoluteTime();
  184.                     m_fElapsedTime = m_fTime - m_fPreviousTime;
  185.                     m_fPreviousTime = m_fTime;
  186.  
  187.                     FrameMove();
  188.  
  189.                     if(m_pSwapChain)
  190.                         Render();
  191.                 }
  192.  
  193.                 m_pPreviewPipeline->SceneReadUnlock(Lock);
  194.             }
  195.         }
  196.     }
  197.  
  198.     UnregisterClass( wndClass.lpszClassName, GetWindowInstance(m_hWndShell) );
  199.  
  200.     return 0;
  201. }
  202.  
  203.  
  204. //-------------------------------------------------------------------------------------
  205. HRESULT CViewer::Create( CPipeline* pPreviewPipeline,    
  206.                          D3DPRESENT_PARAMETERS* pPresentationParameters,
  207.                          const WCHAR* strWindowTitle, 
  208.                          HINSTANCE hInstance, 
  209.                          HICON hIcon, 
  210.                          HMENU hMenu,
  211.                          int width,
  212.                          int height,
  213.                          int x, 
  214.                          int y )
  215. {
  216.     m_pPreviewPipeline = pPreviewPipeline;
  217.     m_dwWidth = width;
  218.     m_dwHeight = height;
  219.  
  220.     m_bDestroyCalled = false;
  221.  
  222.     // Register to receive device state notification
  223.     m_pPreviewPipeline->TriggerDeviceEvents.RegisterEvents( this );
  224.     m_pPreviewPipeline->TriggerManagerEvents.RegisterEvents( this );
  225.     m_pPreviewPipeline->TriggerViewerEvents.RegisterEvents( this );
  226.  
  227.     if( hInstance == NULL )
  228.         hInstance = GetModuleHandle( NULL );
  229.  
  230.     ZeroMemory( &m_CreateArgs, sizeof(CreateArgs) );
  231.     m_CreateArgs.PresentParams = *pPresentationParameters;
  232.     wcsncpy( m_CreateArgs.strWindowTitle, strWindowTitle, MAX_PATH );
  233.     m_CreateArgs.hInstance = hInstance;
  234.     m_CreateArgs.hIcon = hIcon;
  235.     m_CreateArgs.hMenu = hMenu;
  236.     m_CreateArgs.width = width;
  237.     m_CreateArgs.height = height;
  238.     m_CreateArgs.x = x;
  239.     m_CreateArgs.y = y;
  240.  
  241.     // Launch the thread which will create the window and run the message/render loop
  242.     m_hThread = _beginthreadex( NULL, 0, StaticRunThread, this, 0, &m_nThreadID );
  243.     if( m_hThread == NULL )
  244.         return E_FAIL;
  245.  
  246.     Run();
  247.     return S_OK;
  248. }
  249.  
  250.  
  251. //-------------------------------------------------------------------------------------
  252. HRESULT CViewer::Destroy()
  253. {
  254.     if( m_pPreviewPipeline )
  255.     {
  256.         m_pPreviewPipeline->TriggerDeviceEvents.UnregisterEvents( this );
  257.         m_pPreviewPipeline->TriggerManagerEvents.UnregisterEvents( this );
  258.         m_pPreviewPipeline->TriggerViewerEvents.UnregisterEvents( this );
  259.     }
  260.  
  261.     OnD3DDeviceLost();
  262.     OnD3DDeviceDestroy();
  263.  
  264.     m_bDestroyCalled = true;
  265.     WaitForSingleObject( (HANDLE)m_hThread, INFINITE);//100 );//
  266.     TerminateThread((HANDLE)m_hThread, 0);
  267.     CloseHandle( (HANDLE)m_hThread );
  268.  
  269.     m_hWnd= 0;
  270.     m_hThread = 0;
  271.     m_nThreadID = 0;
  272.  
  273.     return S_OK;
  274. }
  275.  
  276.  
  277. //-------------------------------------------------------------------------------------
  278. HRESULT CViewer::Refresh()
  279. {
  280.     HRESULT hr = S_OK;
  281.     
  282.     LPDXCCFRAME pFrameRoot = m_pPreviewPipeline->AccessRoot();
  283.     pFrameRoot->AddRef();
  284.  
  285.     
  286.     m_EffectMap.Reset();
  287.     
  288.     // Traverse the frame tree to register the effects
  289.     hr = RegisterEffectsInFrame( pFrameRoot );
  290.     if( FAILED(hr) )
  291.         goto LCleanReturn;
  292.  
  293.  
  294.     m_EffectMap.AddEffect( m_pDefaultEffect );
  295.  
  296.     hr = S_OK;
  297.     
  298. LCleanReturn:
  299.     SAFE_RELEASE( pFrameRoot );
  300.     return S_OK;
  301. }
  302.  
  303.  
  304.  
  305. //-----------------------------------------------------------------------------
  306. HRESULT CViewer::RegisterEffectsInFrame( IDXCCFrame* pFrame)
  307. {
  308.     HRESULT hr = S_OK;
  309.  
  310.     for( UINT iMesh=0; iMesh < pFrame->NumMembers(); iMesh++ )
  311.     {
  312.         IDXCCMesh* pMesh = NULL;
  313.         hr = pFrame->QueryMember( iMesh, IID_IDXCCMesh, (void**) &pMesh );
  314.         if( FAILED(hr) )
  315.             continue;
  316.  
  317.         V_RETURN( RegisterEffectsInMesh( pMesh ) );
  318.  
  319.         SAFE_RELEASE( pMesh );
  320.     }
  321.  
  322.     for( UINT iChild=0; iChild < pFrame->NumChildren(); iChild++ )
  323.     {
  324.         IDXCCFrame* pChild = NULL;
  325.         hr = pFrame->GetChild( iChild, &pChild );
  326.         if( FAILED(hr) )
  327.             continue;
  328.  
  329.         V_RETURN( RegisterEffectsInFrame( pChild ) );
  330.  
  331.         SAFE_RELEASE( pChild );
  332.     }
  333.  
  334.     return S_OK;
  335. }
  336.  
  337.  
  338. //-------------------------------------------------------------------------------------
  339. HRESULT CViewer::RegisterEffectsInMesh( IDXCCMesh* pMesh )
  340. {
  341.     HRESULT hr;
  342.  
  343.     ID3DXBuffer* pAttribs = NULL;
  344.     DWORD dwNumAttribs = 0;
  345.     V_RETURN( pMesh->GetAttributedMaterialList( &pAttribs, &dwNumAttribs ) );
  346.     
  347.     DWORD* pdwAttrib = NULL;
  348.     if( pAttribs )
  349.          pdwAttrib = (DWORD*) pAttribs->GetBufferPointer();
  350.  
  351.     for ( UINT iMaterial = 0; iMaterial < dwNumAttribs; iMaterial++ )
  352.     {
  353.         DWORD dwAttrib = *( pdwAttrib + iMaterial );
  354.  
  355.         ID3DXEffect* pEffect = NULL;
  356.         hr = pMesh->GetAttributedMaterial( dwAttrib, &pEffect );
  357.         if( FAILED(hr) )
  358.             continue;
  359.     
  360.         if( pEffect )
  361.         {
  362.             hr= m_EffectMap.AddEffect( pEffect );
  363.             if(DXCC_FAILED(hr))
  364.             {
  365.                 SAFE_RELEASE( pEffect );
  366.                 return hr;
  367.             }
  368.         }
  369.         
  370.         SAFE_RELEASE( pEffect );
  371.     }
  372.  
  373.     SAFE_RELEASE( pAttribs );
  374.  
  375.     return S_OK;
  376. }
  377.  
  378.  
  379. //-------------------------------------------------------------------------------------
  380. void CViewer::BindToWindow( HWND hWnd, BOOL bVisible  )
  381. {
  382.     DWORD dwWindowStyle = 0;
  383.     
  384.     if( hWnd != NULL )
  385.     {
  386.         // Docking
  387.         dwWindowStyle |= WS_CHILD;
  388.     }
  389.     else
  390.     {
  391.         // Undocking
  392.         dwWindowStyle |= WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | 
  393.                         WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
  394.  
  395.         if( bVisible )
  396.             dwWindowStyle |= WS_VISIBLE;
  397.  
  398.  
  399.         SetWindowLongPtr( m_hWnd, GWLP_HWNDPARENT, (LONG_PTR)(LONG)(HWND)M3dView::applicationShell() );
  400.  
  401.  
  402.     }
  403.  
  404.     // Switch window styles
  405. #ifdef _WIN64
  406.     LONG_PTR nResult = SetWindowLongPtr( m_hWnd, GWL_STYLE, (LONG_PTR)dwWindowStyle );
  407. #else
  408.     LONG_PTR nResult = SetWindowLongPtr( m_hWnd, GWL_STYLE, (LONG_PTR)(LONG)dwWindowStyle );
  409. #endif 
  410.  
  411.     if( nResult == 0 )
  412.     {
  413.         DXUT_ERR_MSGBOX( L"SetWindowLongPtr", HRESULT_FROM_WIN32(GetLastError()) );
  414.         return;
  415.     }
  416.  
  417.     SetParent( m_hWnd, hWnd );
  418.     
  419.     /*
  420.     WINDOWPLACEMENT placement = {0};
  421.     placement.length = sizeof(WINDOWPLACEMENT);
  422.     placement.showCmd = hWnd ? SW_MAXIMIZE : SW_NORMAL;
  423.     SetWindowPlacement( DXUTGetHWND(), &placement );
  424.     */
  425.  
  426.     nResult = SetWindowPos( m_hWnd, hWnd ? hWnd : 0, 0, 0, m_CreateArgs.width, m_CreateArgs.height, SWP_FRAMECHANGED | SWP_NOMOVE );
  427.     if( nResult == 0 )
  428.     {
  429.         DXTRACE_ERR( L"SetWindowPos", HRESULT_FROM_WIN32(GetLastError()) );
  430.         return;
  431.     }
  432.  
  433.     m_hWndBound = hWnd;
  434.     CheckForResize( true );
  435.     
  436.     // Calling show will in turn call Run(). We're also forcing Maya to completely repaint here
  437.     // to avoid artifacts
  438.     if( bVisible )
  439.     {
  440.         Show();
  441.         ShowWindow( m_hWndShell, SW_HIDE );
  442.         ShowWindow( m_hWndShell, SW_SHOW );
  443.     }
  444. }
  445.  
  446.  
  447. //-------------------------------------------------------------------------------------
  448. void CViewer::CheckForResize( BOOL bForceResize )
  449. {
  450.     HRESULT hr;
  451.  
  452.     RECT rcClient;
  453.     GetClientRect( m_hWndBound ? m_hWndBound : m_hWnd, &rcClient );
  454.     
  455.     DWORD dwWindowWidth = rcClient.right - rcClient.left;
  456.     DWORD dwWindowHeight = rcClient.bottom - rcClient.top;
  457.  
  458.     if(dwWindowWidth != 0 && dwWindowHeight != 0)
  459.     {    
  460.         if( bForceResize || (m_dwWidth != dwWindowWidth) || (m_dwHeight != dwWindowHeight))
  461.         {
  462.             m_dwWidth = dwWindowWidth;
  463.             m_dwHeight = dwWindowHeight;
  464.             
  465.             if( m_hWndBound )
  466.             {
  467.                 SetWindowPos( m_hWnd, HWND_TOP, 
  468.                             0, 0, m_dwWidth, m_dwHeight, 
  469.                             ( m_bVisible && m_dwWidth > 0 ) ? SWP_SHOWWINDOW : SWP_HIDEWINDOW );
  470.             }
  471.  
  472.             // Flush the resources and recreate the swap chain using the new dimensions
  473.             V( OnD3DDeviceLost() );
  474.             V( OnD3DDeviceDestroy() );
  475.             V( OnD3DDeviceCreate() );
  476.             V( OnD3DDeviceReset() );
  477.         }
  478.     }
  479. }
  480.  
  481.  
  482. //-------------------------------------------------------------------------------------
  483. void CViewer::Hide()
  484. {
  485.     m_bVisible = false;
  486.     ShowWindow( m_hWnd, SW_HIDE );
  487.     Pause();
  488. }
  489.  
  490.  
  491. //-------------------------------------------------------------------------------------
  492. void CViewer::Show()
  493. {
  494.     m_bVisible = true;
  495.     ShowWindow( m_hWnd, SW_SHOW );
  496.     Run();
  497. }
  498.  
  499.  
  500. //-------------------------------------------------------------------------------------
  501. HRESULT CViewer::GetD3DSwapChain( IDirect3DSwapChain9** ppSwapChain )
  502. {
  503.     *ppSwapChain = m_pSwapChain;
  504.  
  505.     if( m_pSwapChain == NULL )
  506.         return E_FAIL;
  507.  
  508.     return S_OK;
  509. }
  510.  
  511.  
  512. //-------------------------------------------------------------------------------------
  513. HRESULT CViewer::OnD3DDeviceCreate()
  514. {
  515.     CPipelineLock Lock;
  516.     m_pPreviewPipeline->SceneWriteLock(true, Lock);
  517.  
  518.     HRESULT hr;
  519.     IDirect3DDevice9* pd3dDevice = NULL;
  520.     
  521.     // Setup the camera's view parameters
  522.     D3DXVECTOR3 vecEye(0.0f, 0.0f, -5.0f);
  523.     D3DXVECTOR3 vecAt (0.0f, 0.0f, -0.0f);
  524.     m_Camera.SetViewParams( &vecEye, &vecAt );
  525.  
  526.     CPipelineEngine* pEngine = m_pPreviewPipeline->AccessEngine();
  527.     hr = pEngine->GetD3DDevice( &pd3dDevice );
  528.  
  529.     if( FAILED(hr) || pd3dDevice == NULL )
  530.         goto LCleanReturn;
  531.  
  532.     // Initialize the font
  533.     V( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, 
  534.                          OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  535.                          L"Arial", &m_pFont ) );
  536.     if( FAILED(hr) )
  537.         goto LCleanReturn;
  538.  
  539.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  540.     // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  541.     // processing, and debugging pixel shaders requires REF.  The 
  542.     // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the 
  543.     // shader debugger.  It enables source level debugging, prevents instruction 
  544.     // reordering, prevents dead code elimination, and forces the compiler to compile 
  545.     // against the next higher available software target, which ensures that the 
  546.     // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  547.     // flags will cause slower rendering since the shaders will be unoptimized and 
  548.     // forced into software.  See the DirectX documentation for more information about 
  549.     // using the shader debugger.
  550.     DWORD dwShaderFlags = 0;
  551.     #ifdef DEBUG_VS
  552.         dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  553.     #endif
  554.     #ifdef DEBUG_PS
  555.         dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  556.     #endif
  557.  
  558.     // Find the default effect file
  559.     WCHAR strPath[MAX_PATH+1];
  560.     V_RETURN( DXUTFindDXSDKMediaFileCch( strPath, MAX_PATH, L"UI\\Default.fx" ) );
  561.     V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, strPath, NULL, NULL, dwShaderFlags, NULL, &m_pDefaultEffect, NULL ) );
  562.  
  563.     hr = Refresh();
  564.     if( FAILED(hr) )
  565.         goto LCleanReturn;
  566.  
  567.     // Read the mesh
  568.     //m_Viewer.Create( pd3dDevice, L"tiger\\tiger.x", 0, dwShaderFlags );
  569.     m_LightWidget.StaticOnCreateDevice( pd3dDevice );
  570.    
  571.     m_LightWidget.SetLightDirection( D3DXVECTOR3(1.0f, 0.0f, -1.0f) );
  572.  
  573.     // TODO: move this to the load function and rely on the object radius
  574.     m_Camera.SetRadius( 3.0f, 0.5f, 10.0f );
  575.     m_LightWidget.SetRadius( 0.5f );
  576.  
  577.     hr = S_OK;
  578.  
  579. LCleanReturn:
  580.     SAFE_RELEASE( pd3dDevice );
  581.     
  582.     m_bCreated = true;
  583.  
  584.     m_pPreviewPipeline->SceneWriteUnlock(Lock);
  585.     return hr;
  586. }
  587.  
  588.  
  589. //-------------------------------------------------------------------------------------
  590. HRESULT CViewer::OnD3DDeviceReset()
  591. {
  592.     CPipelineLock Lock;
  593.     m_pPreviewPipeline->SceneWriteLock(true, Lock);
  594.  
  595.     HRESULT hr;
  596.  
  597.     CPipelineEngine* pEngine = m_pPreviewPipeline->AccessEngine();
  598.     IDirect3DSurface9* pBackBuffer = NULL;
  599.     IDirect3DDevice9* pd3dDevice = NULL;
  600.     IDirect3DSurface9* pSurfDeviceDepthStencil = NULL;
  601.     
  602.     hr = pEngine->GetD3DDevice( &pd3dDevice );
  603.     if( FAILED(hr) || pd3dDevice == NULL )
  604.         goto LCleanReturn;
  605.  
  606.     // Create the render chain
  607.     D3DPRESENT_PARAMETERS pp;
  608.     pp = m_CreateArgs.PresentParams;
  609.     pp.BackBufferWidth = m_dwWidth;
  610.     pp.BackBufferHeight = m_dwHeight;
  611.     V( pd3dDevice->CreateAdditionalSwapChain( &pp, &m_pSwapChain ) );
  612.     if( FAILED(hr) )
  613.         goto LCleanReturn;
  614.  
  615.     // Create the depth stencil surface
  616.     V( pd3dDevice->GetDepthStencilSurface( &pSurfDeviceDepthStencil ) );
  617.     if( FAILED(hr) )
  618.         goto LCleanReturn;
  619.  
  620.     D3DSURFACE_DESC desc;
  621.     V( pSurfDeviceDepthStencil->GetDesc( &desc ) );
  622.     if( FAILED(hr) )
  623.         goto LCleanReturn;
  624.  
  625.     V( pd3dDevice->CreateDepthStencilSurface( m_dwWidth, m_dwHeight, desc.Format, desc.MultiSampleType, desc.MultiSampleQuality, false, &m_pDepthStencil, NULL ) );
  626.     if( FAILED(hr) )
  627.         goto LCleanReturn;
  628.  
  629.     V( m_pSwapChain->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer ) );
  630.     if( FAILED(hr) )
  631.         goto LCleanReturn;
  632.  
  633.     D3DSURFACE_DESC BackBufferDesc;
  634.     V( pBackBuffer->GetDesc( &BackBufferDesc ) );
  635.     SAFE_RELEASE( pBackBuffer );
  636.  
  637.     if( FAILED(hr) )
  638.         goto LCleanReturn;
  639.  
  640.     if( m_pDefaultEffect )
  641.         m_pDefaultEffect->OnResetDevice();
  642.  
  643.     m_LightWidget.OnResetDevice( &BackBufferDesc );
  644.  
  645.     if( m_pFont )
  646.     {
  647.         V( m_pFont->OnResetDevice() );
  648.         if( FAILED(hr) )
  649.             goto LCleanReturn;
  650.     }
  651.     
  652.     // Create a sprite to help batch calls when drawing many lines of text
  653.     V( D3DXCreateSprite( pd3dDevice, &m_pTextSprite ) );
  654.     if( FAILED(hr) )
  655.         goto LCleanReturn;
  656.  
  657.     // Setup the camera's projection parameters
  658.     float fAspectRatio;
  659.     fAspectRatio = BackBufferDesc.Width / (FLOAT)BackBufferDesc.Height;
  660.     
  661.     m_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 1000.0f );
  662.     m_Camera.SetWindow( BackBufferDesc.Width, BackBufferDesc.Height );
  663.     m_Camera.SetButtonMasks( MOUSE_LEFT_BUTTON, MOUSE_WHEEL, MOUSE_MIDDLE_BUTTON );
  664.  
  665.     hr = S_OK;
  666.  
  667. LCleanReturn:
  668.     SAFE_RELEASE( pBackBuffer );
  669.     SAFE_RELEASE( pd3dDevice );
  670.     SAFE_RELEASE( pSurfDeviceDepthStencil );
  671.  
  672.     Run();
  673.  
  674.     m_pPreviewPipeline->SceneWriteUnlock(Lock);
  675.     return hr;
  676. }
  677.  
  678.  
  679.  
  680. //--------------------------------------------------------------------------------------
  681. // Before handling window messages, the sample framework passes incoming windows 
  682. // messages to the application through this callback function. If the application sets 
  683. // *pbNoFurtherProcessing to TRUE, then the sample framework will not process this message.
  684. //--------------------------------------------------------------------------------------
  685. LRESULT CViewer::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  686. {
  687.     // Pass windows messages to camera so it can respond to user input
  688.     m_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
  689.     m_LightWidget.HandleMessages( hWnd, uMsg, wParam, lParam );
  690.  
  691.     switch( uMsg )
  692.     {
  693.         case WM_CLOSE:
  694.             Hide();
  695.             return 0;
  696.  
  697.         case WM_PAINT:
  698.             Render();
  699.             break;
  700.  
  701.         case WM_KEYDOWN:
  702.         {
  703.             switch( wParam )
  704.             {
  705.                 case VK_ESCAPE:
  706.                     Destroy();
  707.                     break;
  708.             }
  709.  
  710.             break;
  711.         }
  712.  
  713.         case WM_TIMER:
  714.             CheckForResize();
  715.             break;
  716.     }
  717.  
  718.     return DefWindowProc( hWnd, uMsg, wParam, lParam );
  719. }
  720.  
  721.  
  722.  
  723. //--------------------------------------------------------------------------------------
  724. // This callback function will be called once at the beginning of every frame. This is the
  725. // best location for your application to handle updates to the scene, but is not 
  726. // intended to contain actual rendering calls, which should instead be placed in the 
  727. // OnFrameRender callback.  
  728. //--------------------------------------------------------------------------------------
  729. void CViewer::FrameMove()
  730. {
  731.     // Update the camera's position based on user input 
  732.     m_Camera.FrameMove( m_fElapsedTime );
  733. }
  734.  
  735.  
  736. //--------------------------------------------------------------------------------------
  737. // This callback function will be called at the end of every frame to perform all the 
  738. // rendering calls for the scene, and it will also be called if the window needs to be 
  739. // repainted. After this function has returned, the sample framework will call 
  740. // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
  741. //--------------------------------------------------------------------------------------
  742. void CViewer::Render()
  743. {
  744.     HRESULT hr;
  745.     D3DXMATRIXA16 mWorld;
  746.     D3DXMATRIXA16 mView;
  747.     D3DXMATRIXA16 mProj;
  748.     D3DXMATRIXA16 mWorldViewProjection;
  749.  
  750.     
  751.     if( m_bCreated == false || m_pSwapChain == NULL)
  752.         return;
  753.  
  754.     // Get read lock
  755.     CPipelineLock SceneLock;
  756.  
  757.  
  758.     //TODO:  note when there are multiple viewer ReadLock will not be enough.
  759.     //they will need to be in 1 thread or use a locking mechanism to make sure
  760.     //they are not colliding on the state changes.
  761.     if(m_pPreviewPipeline->SceneReadLock( false , SceneLock))
  762.     {
  763.  
  764.         CPipelineEngine* pEngine = m_pPreviewPipeline->AccessEngine();
  765.         IDirect3DDevice9* pd3dDevice = NULL;
  766.         hr = pEngine->GetD3DDevice( &pd3dDevice );
  767.         if( FAILED(hr) || pd3dDevice == NULL )
  768.             return;
  769.  
  770.         IDirect3DSurface9* pSurfOldRenderTarget = NULL;
  771.         V( pd3dDevice->GetRenderTarget( 0, &pSurfOldRenderTarget ) );
  772.  
  773.         IDirect3DSurface9* pSurfOldDepthStencil = NULL;
  774.         V( pd3dDevice->GetDepthStencilSurface( &pSurfOldDepthStencil ) );
  775.         V( pd3dDevice->SetDepthStencilSurface( m_pDepthStencil ) );
  776.  
  777.         IDirect3DSurface9* pSurfNewRenderTarget = NULL;
  778.         hr= m_pSwapChain->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pSurfNewRenderTarget );
  779.         V( pd3dDevice->SetRenderTarget( 0, pSurfNewRenderTarget ) );
  780.            SAFE_RELEASE( pSurfNewRenderTarget );
  781.      
  782.         // Clear the render target and the zbuffer 
  783.         V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 100), 1.0f, 0) );
  784.  
  785.         // Render the scene
  786.         if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  787.         {
  788.             // Get the projection & view matrix from the camera class
  789.             mWorld = *m_Camera.GetWorldMatrix();
  790.             mView = *m_Camera.GetViewMatrix();
  791.             mProj = *m_Camera.GetProjMatrix();
  792.  
  793.             mView= g_PreviewPipeline.PerspectiveCamera_GetView();
  794.              mProj= g_PreviewPipeline.PerspectiveCamera_GetProjection();
  795.             
  796.             // Adjust for aspect ratio
  797.             mProj._22 *= (float)m_dwWidth / m_dwHeight;
  798.  
  799.             m_EffectMap.SetWorldMatrix( &mWorld );
  800.             m_EffectMap.SetViewMatrix(&mView ); 
  801.             m_EffectMap.SetProjectionMatrix( &mProj ); 
  802.  
  803.             m_EffectMap.SetStandardParameter( DXUT_Time, DXUT_Geometry, 0, (float*) &m_fTime, 1 );  
  804.             m_EffectMap.SetStandardParameter( DXUT_Direction, DXUT_Light, 0, (float*) &m_LightWidget.GetLightDirection(), 3 );
  805.  
  806.             //debug
  807.             D3DXVECTOR4 vDiffuse( 1, 1, 1, 1 );
  808.             m_EffectMap.SetStandardParameter( DXUT_Diffuse, DXUT_Light, 0, (float*) &vDiffuse, 4 );
  809.  
  810.             // debug
  811.  
  812.             // Set the time parameter
  813.             m_EffectMap.SetStandardParameter( DXUT_Time, DXUT_Geometry, 0, &m_fTime, 1 );
  814.  
  815.             
  816.             LPDXCCFRAME pFrameRoot = m_pPreviewPipeline->AccessRoot();
  817.             pFrameRoot->AddRef();
  818.             
  819.             if( pFrameRoot != NULL )
  820.                 DrawFrame( pFrameRoot );
  821.             
  822.             SAFE_RELEASE( pFrameRoot );
  823.  
  824.  
  825.             //TODO: get the eye point from the maya camera
  826.             //V( m_LightWidget.OnRender( D3DCOLOR_ARGB(255, 255, 255, 255), &mView, &mProj, m_Camera.GetEyePt() ) );
  827.             
  828.             //if( m_pFont && m_pTextSprite )
  829.             //    RenderText();
  830.  
  831.             V( pd3dDevice->EndScene() );
  832.  
  833.             if(m_pSwapChain)
  834.                 V( m_pSwapChain->Present( NULL, NULL, m_hWnd, NULL, 0 ) );
  835.  
  836.         }
  837.  
  838.         pd3dDevice->SetRenderTarget( 0, pSurfOldRenderTarget );
  839.         SAFE_RELEASE( pSurfOldRenderTarget );
  840.         pd3dDevice->SetDepthStencilSurface( pSurfOldDepthStencil );
  841.         SAFE_RELEASE( pSurfOldDepthStencil );
  842.  
  843.         SAFE_RELEASE( pd3dDevice );
  844.         
  845.         m_pPreviewPipeline->SceneReadUnlock(SceneLock);
  846.     }
  847.  
  848. }
  849.  
  850.  
  851. //-----------------------------------------------------------------------------
  852. // Name: DrawFrame()
  853. // Desc: Called to render a frame in the hierarchy
  854. //-----------------------------------------------------------------------------
  855. void CViewer::DrawFrame( IDXCCFrame* pFrame)
  856. {
  857.     HRESULT hr = S_OK;
  858.  
  859.     if(pFrame->NumMembers() > 0)
  860.     {
  861.         D3DXMATRIXA16 mWorld;
  862.         D3DXMATRIXA16 mView;
  863.         D3DXMATRIXA16 mProj;
  864.         D3DXMATRIXA16 mWorldViewProjection;
  865.  
  866.  
  867.         mWorld= D3DXMATRIXA16(*pFrame->GetWorldMatrix());
  868.  
  869.         m_EffectMap.SetWorldMatrix(&mWorld );
  870.     }
  871.  
  872.     for( UINT iMesh=0; iMesh < pFrame->NumMembers(); iMesh++ )
  873.     {
  874.         IDXCCMesh* pMesh = NULL;
  875.         hr = pFrame->QueryMember( iMesh, IID_IDXCCMesh, (void**) &pMesh );
  876.         if( FAILED(hr) )
  877.             continue;
  878.  
  879.         DrawMesh( pMesh );
  880.  
  881.         SAFE_RELEASE(pMesh);
  882.     }
  883.  
  884.     for( UINT iChild=0; iChild < pFrame->NumChildren(); iChild++ )
  885.     {
  886.         IDXCCFrame* pChild = NULL;
  887.         hr = pFrame->GetChild( iChild, &pChild );
  888.         if( FAILED(hr) )
  889.             continue;
  890.  
  891.         DrawFrame( pChild );
  892.  
  893.         SAFE_RELEASE(pChild);
  894.     }
  895. }
  896.  
  897.  
  898. //--------------------------------------------------------------------------------------
  899. void CViewer::DrawMesh( IDXCCMesh* pMesh )
  900. {
  901.     HRESULT hr;
  902.  
  903.     ID3DXBuffer* pAttribs = NULL;
  904.     DWORD dwNumAttribs = 0;
  905.     hr = pMesh->GetAttributedMaterialList( &pAttribs, &dwNumAttribs );
  906.     if( FAILED(hr) )
  907.         return;
  908.  
  909.     DWORD* pdwAttrib = NULL;
  910.     if( pAttribs )
  911.          pdwAttrib = (DWORD*) pAttribs->GetBufferPointer();
  912.  
  913.     if( dwNumAttribs > 0 )
  914.     {
  915.         for( UINT iMaterial = 0; iMaterial < dwNumAttribs; iMaterial++ )
  916.         {
  917.             DWORD dwAttrib = *( pdwAttrib + iMaterial );
  918.  
  919.             ID3DXEffect* pEffect = NULL;
  920.             hr = pMesh->GetAttributedMaterial( dwAttrib, &pEffect );
  921.             if( FAILED(hr))
  922.                 continue;
  923.             
  924.             if(!pEffect)
  925.             {
  926.                 m_pDefaultEffect->AddRef();
  927.                 pEffect=m_pDefaultEffect;
  928.             }
  929.         
  930.             D3DXHANDLE hTechnique;
  931.             V( pEffect->FindNextValidTechnique( NULL, &hTechnique ) );
  932.             V( pEffect->SetTechnique( hTechnique ) );
  933.  
  934.             UINT numPasses;
  935.             V( pEffect->Begin(&numPasses, 0) );
  936.  
  937.             for( UINT iPass = 0; iPass < numPasses; iPass++ )
  938.             {
  939.                 V( pEffect->BeginPass(iPass) );
  940.  
  941.                 // The effect interface queues up the changes and performs them 
  942.                 // with the CommitChanges call. You do not need to call CommitChanges if 
  943.                 // you are not setting any parameters between the BeginPass and EndPass.
  944.                 // V( pEffect->CommitChanges() );
  945.  
  946.                 // Render the mesh with the applied technique
  947.                 V( pMesh->DrawSubset( dwAttrib ) );
  948.                 
  949.                 V( pEffect->EndPass() );
  950.             }
  951.             V( pEffect->End() );
  952.  
  953.             SAFE_RELEASE(pEffect);
  954.         }
  955.     }
  956.     else
  957.     {   
  958.         if( m_pDefaultEffect )
  959.         {
  960.             D3DXHANDLE hTechnique;
  961.             V( m_pDefaultEffect->FindNextValidTechnique( NULL, &hTechnique ) );
  962.             V( m_pDefaultEffect->SetTechnique( hTechnique ) );
  963.  
  964.             UINT numPasses;
  965.             V( m_pDefaultEffect->Begin(&numPasses, 0) );
  966.  
  967.             for( UINT iPass = 0; iPass < numPasses; iPass++ )
  968.             {
  969.                 V( m_pDefaultEffect->BeginPass(iPass) );
  970.  
  971.                 // The effect interface queues up the changes and performs them 
  972.                 // with the CommitChanges call. You do not need to call CommitChanges if 
  973.                 // you are not setting any parameters between the BeginPass and EndPass.
  974.                 // V( pEffect->CommitChanges() );
  975.  
  976.                 // Render the mesh with the applied technique
  977.                 V( pMesh->DrawSubset( 0 ) );
  978.                 
  979.                 V( m_pDefaultEffect->EndPass() );
  980.             }
  981.             V( m_pDefaultEffect->End() );
  982.         }
  983.       
  984.     }
  985.  
  986.     SAFE_RELEASE( pAttribs );
  987. }
  988.  
  989.  
  990. //--------------------------------------------------------------------------------------
  991. // Render the help and statistics text. This function uses the ID3DXFont interface for 
  992. // efficient text rendering.
  993. //--------------------------------------------------------------------------------------
  994. void CViewer::RenderText()
  995. {
  996.     // The helper object simply helps keep track of text position, and color
  997.     // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
  998.     // If NULL is passed in as the sprite object, then it will work however the 
  999.     // pFont->DrawText() will not be batched together.  Batching calls will improves performance.
  1000.     CDXUTTextHelper txtHelper( m_pFont, m_pTextSprite, 15 );
  1001.  
  1002.     // Output statistics
  1003.     txtHelper.Begin();
  1004.     txtHelper.SetInsertionPos( 5, 5 );
  1005.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  1006.  
  1007.     WCHAR strBuffer[MAX_PATH+1] = {0};
  1008.     _snwprintf( strBuffer, MAX_PATH, L"Time: %f", m_fTime );
  1009.     txtHelper.DrawTextLine( strBuffer );
  1010.     
  1011.     txtHelper.End();
  1012. }
  1013.  
  1014.  
  1015.  
  1016. //-------------------------------------------------------------------------------------
  1017. HRESULT CViewer::OnD3DDeviceLost()
  1018.  
  1019.     CPipelineLock Lock;
  1020.     m_pPreviewPipeline->SceneWriteLock(true, Lock);
  1021.  
  1022.     UINT ref;
  1023.  
  1024.     Pause();
  1025.  
  1026.     m_LightWidget.StaticOnLostDevice();
  1027.     
  1028.     if( m_pFont )
  1029.         m_pFont->OnLostDevice();
  1030.     
  1031.     if( m_pDefaultEffect )
  1032.         m_pDefaultEffect->OnLostDevice();
  1033.  
  1034.     ref= DXCC_RELEASE( m_pDepthStencil );
  1035.     ref= DXCC_RELEASE( m_pTextSprite );
  1036.     ref= DXCC_RELEASE( m_pSwapChain );
  1037.  
  1038.     m_pPreviewPipeline->SceneWriteUnlock(Lock);
  1039.     return S_OK;
  1040. }
  1041.  
  1042.  
  1043. //-------------------------------------------------------------------------------------
  1044. HRESULT CViewer::OnD3DDeviceDestroy()
  1045. {
  1046.     CPipelineLock Lock;
  1047.     m_pPreviewPipeline->SceneWriteLock(true, Lock);
  1048.  
  1049.     UINT ref;
  1050.     m_bCreated = false;
  1051.  
  1052.     m_EffectMap.Reset();
  1053.     m_LightWidget.StaticOnDestroyDevice();
  1054.     ref= DXCC_RELEASE( m_pFont );
  1055.     ref= DXCC_RELEASE( m_pTextSprite );
  1056.     ref= DXCC_RELEASE( m_pDefaultEffect );
  1057.  
  1058.     m_pPreviewPipeline->SceneWriteUnlock(Lock);
  1059.     return S_OK;
  1060. }
  1061.  
  1062.  
  1063.  
  1064.