home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / bin / DXUtils / AppWizard / DXAppwiz.awx / TEMPLATE / D3D_DLG.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-25  |  106.3 KB  |  3,011 lines

  1. //-----------------------------------------------------------------------------
  2. // File: $$root$$.cpp
  3. //
  4. // Desc: DirectX MFC dialog application created by the DirectX AppWizard
  5. //-----------------------------------------------------------------------------
  6. #define STRICT
  7. $$IF(DINPUT)
  8. #define DIRECTINPUT_VERSION 0x0800
  9. $$ENDIF
  10. #include "stdafx.h"
  11. #include "$$root$$.h"
  12.  
  13.  
  14.  
  15.  
  16. //-----------------------------------------------------------------------------
  17. // Application globals
  18. //-----------------------------------------------------------------------------
  19. TCHAR*          g_strAppTitle       = _T( "$$root$$" );
  20. CApp            g_App;
  21. HINSTANCE       g_hInst = NULL;
  22. CAppForm*       g_AppFormView = NULL;
  23.  
  24.  
  25.  
  26.  
  27. //-----------------------------------------------------------------------------
  28. // The MFC macros are all listed here
  29. //-----------------------------------------------------------------------------
  30. IMPLEMENT_DYNCREATE( CAppDoc,      CDocument )
  31. IMPLEMENT_DYNCREATE( CAppFrameWnd, CFrameWnd )
  32. IMPLEMENT_DYNCREATE( CAppForm,     CFormView )
  33.  
  34.  
  35.  
  36.  
  37. BEGIN_MESSAGE_MAP( CApp, CWinApp )
  38.     //{{AFX_MSG_MAP(CApp)
  39.     //}}AFX_MSG_MAP
  40. END_MESSAGE_MAP()
  41.  
  42.  
  43.  
  44.  
  45. BEGIN_MESSAGE_MAP( CAppForm, CFormView )
  46.     //{{AFX_MSG_MAP(CAppForm)
  47.     ON_COMMAND(    IDC_VIEWFULLSCREEN, OnToggleFullScreen )
  48.     ON_BN_CLICKED(IDC_CHANGEDEVICE, OnChangeDevice)
  49.     //}}AFX_MSG_MAP
  50. END_MESSAGE_MAP()
  51.  
  52.  
  53.  
  54.  
  55. BEGIN_MESSAGE_MAP(CAppDoc, CDocument)
  56.     //{{AFX_MSG_MAP(CAppDoc)
  57.             // NOTE - the ClassWizard will add and remove mapping macros here.
  58.             //    DO NOT EDIT what you see in these blocks of generated code!
  59.     //}}AFX_MSG_MAP
  60. END_MESSAGE_MAP()
  61.  
  62.  
  63.  
  64.  
  65. BEGIN_MESSAGE_MAP(CAppFrameWnd, CFrameWnd)
  66.     //{{AFX_MSG_MAP(CAppFrameWnd)
  67.     ON_COMMAND(IDM_CHANGEDEVICE, OnChangeDevice)
  68. $$IF(ACTIONMAPPER)
  69.     ON_COMMAND(IDM_CONFIGINPUT, OnConfigInput)
  70. $$ENDIF
  71. $$IF(DPLAYVOICE)
  72.     ON_COMMAND(IDM_CONFIGVOICE, OnConfigVoice)
  73. $$ENDIF
  74.     //}}AFX_MSG_MAP
  75. END_MESSAGE_MAP()
  76.  
  77.  
  78.  
  79.  
  80. //-----------------------------------------------------------------------------
  81. // Name: CAppForm()
  82. // Desc: Constructor for the dialog resource form
  83. //-----------------------------------------------------------------------------
  84. CAppForm::CAppForm()
  85.          :CFormView( IDD_FORMVIEW )
  86. {
  87.     //{{AFX_DATA_INIT(CAppForm)
  88.         // NOTE: the ClassWizard will add member initialization here
  89.     //}}AFX_DATA_INIT
  90.  
  91.     g_AppFormView          = this;
  92.     m_hwndRenderWindow     = NULL;
  93.     m_hwndRenderFullScreen = NULL;
  94.     m_hWndTopLevelParent   = NULL;
  95.  
  96.     // Override some CD3DApplication defaults:
  97.     m_dwCreationWidth           = 500;
  98.     m_dwCreationHeight          = 375;
  99.     m_strWindowTitle            = TEXT( "$$root$$" );
  100.     m_bUseDepthBuffer           = TRUE;
  101.  
  102. $$IF(D3DFONT)
  103.     // Create a D3D font using d3dfont.cpp
  104.     m_pFont                     = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
  105. $$ELSE
  106.     m_pD3DXFont                 = NULL;
  107. $$ENDIF
  108.     m_bLoadingApp               = TRUE;
  109. $$IF(SHOW_TRIANGLE)
  110.     m_pVB                       = NULL;
  111. $$ENDIF
  112. $$IF(SHOW_TEAPOT)
  113.     m_pD3DXMesh                 = NULL;
  114. $$ENDIF
  115. $$IF(KEYBOARD)
  116.     m_pDI                       = NULL;
  117.     m_pKeyboard                 = NULL;
  118. $$ENDIF
  119. $$IF(ACTIONMAPPER)
  120.     m_pInputDeviceManager       = NULL;
  121. $$ENDIF
  122. $$IF(DMUSIC || DSOUND)
  123. $$IF(DMUSIC)
  124.     m_pMusicManager             = NULL;
  125.     m_pBounceSound              = NULL;
  126. $$ELSE
  127.     m_pSoundManager             = NULL;
  128.     m_pBounceSound              = NULL;
  129. $$ENDIF
  130. $$ENDIF
  131. $$IF(ACTIONMAPPER)
  132.     m_pDIConfigSurface          = NULL;
  133. $$ENDIF
  134.  
  135.     ZeroMemory( &m_UserInput, sizeof(m_UserInput) );
  136.     m_fWorldRotX                = 0.0f;
  137.     m_fWorldRotY                = 0.0f;
  138. $$IF(DPLAY)
  139.  
  140.     m_pDP                       = NULL;    
  141.     m_pNetConnectWizard         = NULL;    
  142.     m_pLobbiedApp               = NULL;    
  143.     m_bWasLobbyLaunched         = FALSE;   
  144.     m_dpnidLocalPlayer          = 0;       
  145.     m_lNumberOfActivePlayers    = 0;       
  146.     m_pLocalPlayerInfo          = NULL;
  147.     m_hrNet                     = S_OK;
  148.     m_fWorldSyncTimer           = 0.0f;
  149.     m_bHostPausing              = FALSE;
  150.  
  151.     ZeroMemory( &m_PlayInfoList, sizeof(APP_PLAYER_INFO) );
  152.     m_PlayInfoList.pNext = &m_PlayInfoList;
  153.     m_PlayInfoList.pPrev = &m_PlayInfoList;
  154. $$ENDIF
  155. $$IF(DPLAYVOICE)
  156.  
  157.     m_pNetVoice                 = NULL;
  158. $$ENDIF
  159.  
  160.     // Read settings from registry
  161.     ReadSettings();
  162. }
  163.  
  164.  
  165.  
  166.  
  167. //-----------------------------------------------------------------------------
  168. // Name: CAppForm::OneTimeSceneInit()
  169. // Desc: Called during initial app startup, this function performs all the
  170. //       permanent initialization.
  171. //-----------------------------------------------------------------------------
  172. HRESULT CAppForm::OneTimeSceneInit()
  173. {
  174.     // TODO: perform one time initialization
  175.  
  176. $$IF(DPLAY)
  177.     // Init COM so we can use CoCreateInstance.  And be sure to init 
  178.     // COM as multithreaded when using DirectPlay
  179.     HRESULT hr;
  180.     if( FAILED( hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ) ) )
  181.         return hr;
  182.  
  183. $$ENDIF
  184. $$IF(DINPUT)
  185.     // Initialize DirectInput
  186.     InitInput( m_hWndTopLevelParent );
  187.  
  188. $$ENDIF
  189. $$IF(DMUSIC || DSOUND)
  190.     // Initialize audio
  191.     InitAudio( m_hWndTopLevelParent );
  192.  
  193. $$ENDIF
  194. $$IF(DPLAY)
  195.     // Initialize DirectPlay
  196.     InitDirectPlay();
  197.  
  198.     // Create a new DirectPlay session or join to an existing DirectPlay session
  199.     if( FAILED( hr = ConnectViaDirectPlay() ) )
  200.         return hr;
  201.  
  202. $$ENDIF
  203.     m_bLoadingApp = FALSE;
  204.  
  205.     return S_OK;
  206. }
  207.  
  208.  
  209.  
  210.  
  211. //-----------------------------------------------------------------------------
  212. // Name: ReadSettings()
  213. // Desc: Read the app settings from the registry
  214. //-----------------------------------------------------------------------------
  215. VOID CAppForm::ReadSettings()
  216. {
  217.     HKEY hkey;
  218.     if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, DXAPP_KEY, 
  219.         0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  220.     {
  221.         // TODO: change as needed
  222.  
  223.         // Read the stored window width/height.  This is just an example,
  224.         // of how to use DXUtil_Read*() functions.
  225.         DXUtil_ReadIntRegKey( hkey, TEXT("Width"), &m_dwCreationWidth, m_dwCreationWidth );
  226.         DXUtil_ReadIntRegKey( hkey, TEXT("Height"), &m_dwCreationHeight, m_dwCreationHeight );
  227.  
  228. $$IF(DPLAY)
  229.         // Read the saved strings needed by DirectPlay
  230.         DXUtil_ReadStringRegKey( hkey, TEXT("Player Name"), 
  231.                                  m_strLocalPlayerName, MAX_PATH, TEXT("$$root$$ Player") );
  232.         DXUtil_ReadStringRegKey( hkey, TEXT("Session Name"), 
  233.                                  m_strSessionName, MAX_PATH, TEXT("$$root$$ Game") );
  234.         DXUtil_ReadStringRegKey( hkey, TEXT("Preferred Provider"), 
  235.                                  m_strPreferredProvider, MAX_PATH, 
  236.                                  TEXT("DirectPlay8 TCP/IP Service Provider") );
  237.  
  238. $$ENDIF
  239.         RegCloseKey( hkey );
  240.     }
  241. }
  242.  
  243.  
  244.  
  245.  
  246. //-----------------------------------------------------------------------------
  247. // Name: WriteSettings()
  248. // Desc: Write the app settings to the registry
  249. //-----------------------------------------------------------------------------
  250. VOID CAppForm::WriteSettings()
  251. {
  252.     HKEY hkey;
  253.     DWORD dwType = REG_DWORD;
  254.     DWORD dwLength = sizeof(DWORD);
  255.  
  256.     if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, DXAPP_KEY, 
  257.         0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  258.     {
  259.         // TODO: change as needed
  260.  
  261.         // Write the window width/height.  This is just an example,
  262.         // of how to use DXUtil_Write*() functions.
  263.         DXUtil_WriteIntRegKey( hkey, TEXT("Width"), m_rcWindowClient.right );
  264.         DXUtil_WriteIntRegKey( hkey, TEXT("Height"), m_rcWindowClient.bottom );
  265.  
  266. $$IF(DPLAY)
  267.         // Save the strings used by DirectPlay that were entered via the UI
  268.         DXUtil_WriteStringRegKey( hkey, TEXT("Player Name"), m_strLocalPlayerName );
  269.         DXUtil_WriteStringRegKey( hkey, TEXT("Session Name"), m_strSessionName );
  270.         DXUtil_WriteStringRegKey( hkey, TEXT("Preferred Provider"), m_strPreferredProvider );
  271.         
  272. $$ENDIF
  273.         RegCloseKey( hkey );
  274.     }
  275. }
  276.  
  277.  
  278.  
  279.  
  280.  
  281. $$IF(ACTIONMAPPER)
  282. //-----------------------------------------------------------------------------
  283. // Name: StaticInputAddDeviceCB()
  284. // Desc: Static callback helper to call into CAppForm class
  285. //-----------------------------------------------------------------------------
  286. HRESULT CALLBACK CAppForm::StaticInputAddDeviceCB( 
  287.                                          CInputDeviceManager::DeviceInfo* pDeviceInfo, 
  288.                                          const DIDEVICEINSTANCE* pdidi, 
  289.                                          LPVOID pParam )
  290. {
  291.     CAppForm* pApp = (CAppForm*) pParam;
  292.     return pApp->InputAddDeviceCB( pDeviceInfo, pdidi );
  293. }
  294.  
  295.  
  296.  
  297.  
  298. //-----------------------------------------------------------------------------
  299. // Name: InputAddDeviceCB()
  300. // Desc: Called from CInputDeviceManager whenever a device is added. 
  301. //       Set the dead zone, and creates a new InputDeviceState for each device
  302. //-----------------------------------------------------------------------------
  303. HRESULT CAppForm::InputAddDeviceCB( CInputDeviceManager::DeviceInfo* pDeviceInfo, 
  304.                                                    const DIDEVICEINSTANCE* pdidi )
  305. {
  306.     // Setup the deadzone 
  307.     DIPROPDWORD dipdw;
  308.     dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
  309.     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  310.     dipdw.diph.dwObj        = 0;
  311.     dipdw.diph.dwHow        = DIPH_DEVICE;
  312.     dipdw.dwData            = 500;
  313.     pDeviceInfo->pdidDevice->SetProperty( DIPROP_DEADZONE, &dipdw.diph );
  314.  
  315.     // Create a new InputDeviceState for each device so the 
  316.     // app can record its state 
  317.     InputDeviceState* pNewInputDeviceState = new InputDeviceState;
  318.     ZeroMemory( pNewInputDeviceState, sizeof(InputDeviceState) );
  319.     pDeviceInfo->pParam = (LPVOID) pNewInputDeviceState;
  320.  
  321.     return S_OK;
  322. }
  323.  
  324.  
  325.  
  326.  
  327. $$ENDIF
  328. $$IF(DINPUT)
  329. //-----------------------------------------------------------------------------
  330. // Name: InitInput()
  331. // Desc: Initialize DirectInput objects
  332. //-----------------------------------------------------------------------------
  333. HRESULT CAppForm::InitInput( HWND hWnd )
  334. {
  335.     HRESULT hr;
  336.  
  337. $$IF(KEYBOARD)
  338.     // Create a IDirectInput8*
  339.     if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
  340.                                          IID_IDirectInput8, (VOID**)&m_pDI, NULL ) ) )
  341.         return DXTRACE_ERR_NOMSGBOX( "DirectInput8Create", hr );
  342.     
  343.     // Create a IDirectInputDevice8* for the keyboard
  344.     if( FAILED( hr = m_pDI->CreateDevice( GUID_SysKeyboard, &m_pKeyboard, NULL ) ) )
  345.         return DXTRACE_ERR_NOMSGBOX( "CreateDevice", hr );
  346.     
  347.     // Set the keyboard data format
  348.     if( FAILED( hr = m_pKeyboard->SetDataFormat( &c_dfDIKeyboard ) ) )
  349.         return DXTRACE_ERR_NOMSGBOX( "SetDataFormat", hr );
  350.     
  351.     // Set the cooperative level on the keyboard
  352.     if( FAILED( hr = m_pKeyboard->SetCooperativeLevel( hWnd, 
  353.                                             DISCL_NONEXCLUSIVE | 
  354.                                             DISCL_FOREGROUND | 
  355.                                             DISCL_NOWINKEY ) ) )
  356.         return DXTRACE_ERR_NOMSGBOX( "SetCooperativeLevel", hr );
  357.  
  358.     // Acquire the keyboard
  359.     m_pKeyboard->Acquire();
  360. $$ENDIF
  361. $$IF(ACTIONMAPPER)
  362.     // Setup action format for the actual gameplay
  363.     ZeroMemory( &m_diafGame, sizeof(DIACTIONFORMAT) );
  364.     m_diafGame.dwSize          = sizeof(DIACTIONFORMAT);
  365.     m_diafGame.dwActionSize    = sizeof(DIACTION);
  366.     m_diafGame.dwDataSize      = NUMBER_OF_GAMEACTIONS * sizeof(DWORD);
  367.     m_diafGame.guidActionMap   = g_guidApp;
  368.  
  369.     // TODO: change the genre as needed
  370.     m_diafGame.dwGenre         = DIVIRTUAL_CAD_3DCONTROL; 
  371.  
  372.     m_diafGame.dwNumActions    = NUMBER_OF_GAMEACTIONS;
  373.     m_diafGame.rgoAction       = g_rgGameAction;
  374.     m_diafGame.lAxisMin        = -100;
  375.     m_diafGame.lAxisMax        = 100;
  376.     m_diafGame.dwBufferSize    = 16;
  377.     _tcscpy( m_diafGame.tszActionMap, _T("$$root$$ Game") );
  378.  
  379.     // Create a new input device manager
  380.     m_pInputDeviceManager = new CInputDeviceManager();
  381.  
  382.     if( FAILED( hr = m_pInputDeviceManager->Create( hWnd, NULL, m_diafGame, 
  383.                                                     StaticInputAddDeviceCB, this ) ) )
  384.         return DXTRACE_ERR_NOMSGBOX( "m_pInputDeviceManager->Create", hr );
  385. $$ENDIF
  386.  
  387.     return S_OK;
  388. }
  389.  
  390.  
  391.  
  392.  
  393. $$ENDIF
  394. $$IF(DMUSIC || DSOUND)
  395. //-----------------------------------------------------------------------------
  396. // Name: InitAudio()
  397. // Desc: Initialize DirectX audio objects
  398. //-----------------------------------------------------------------------------
  399. HRESULT CAppForm::InitAudio( HWND hWnd )
  400. {
  401.     HRESULT hr;
  402.  
  403. $$IF(DMUSIC)
  404.     // Create the music manager class, used to create the sounds
  405.     m_pMusicManager = new CMusicManager();
  406.     if( FAILED( hr = m_pMusicManager->Initialize( hWnd ) ) )
  407.         return DXTRACE_ERR_NOMSGBOX( "m_pMusicManager->Initialize", hr );
  408.  
  409.     // Instruct the music manager where to find the files
  410.     // TODO: Set this to the media directory, or use resources
  411.     TCHAR szPath[MAX_PATH];
  412.     GetCurrentDirectory( MAX_PATH, szPath ); 
  413.     m_pMusicManager->SetSearchDirectory( szPath );
  414.  
  415.     // TODO: load the sounds from resources (or files)
  416.     m_pMusicManager->CreateSegmentFromResource( &m_pBounceSound, _T("BOUNCE"), _T("WAVE") );
  417.  
  418. $$ELSE
  419.     // Create a static IDirectSound in the CSound class.  
  420.     // Set coop level to DSSCL_PRIORITY, and set primary buffer 
  421.     // format to stereo, 22kHz and 16-bit output.
  422.     m_pSoundManager = new CSoundManager();
  423.  
  424.     if( FAILED( hr = m_pSoundManager->Initialize( hWnd, DSSCL_PRIORITY, 2, 22050, 16 ) ) )
  425.         return DXTRACE_ERR_NOMSGBOX( TEXT("m_pSoundManager->Initialize"), hr );
  426.  
  427.     // TODO: load the sounds from resources (or files)
  428.     m_pSoundManager->Create( &m_pBounceSound, TEXT("BOUNCE"), 0, GUID_NULL, 5 );
  429.  
  430. $$ENDIF
  431.     return S_OK;
  432. }
  433.  
  434.  
  435.  
  436.  
  437. $$ENDIF
  438. $$IF(DPLAY)
  439. //-----------------------------------------------------------------------------
  440. // Name: InitDirectPlay()
  441. // Desc: Initialize DirectPlay
  442. //-----------------------------------------------------------------------------
  443. HRESULT CAppForm::InitDirectPlay()
  444. {
  445.     // Initialize critical sections
  446.     InitializeCriticalSection( &g_csPlayerContext );
  447.     InitializeCriticalSection( &g_csWorldStateContext );
  448.  
  449.     // Create helper class
  450.     m_pNetConnectWizard = new CNetConnectWizard( g_hInst, m_hWndTopLevelParent, 
  451.                                                  m_strWindowTitle, &g_guidApp );
  452. $$IF(DPLAYVOICE)
  453.     m_pNetVoice         = new CNetVoice( StaticDirectPlayVoiceClientMessageHandler, StaticDirectPlayVoiceServerMessageHandler );
  454. $$ENDIF
  455.  
  456.     DPNHANDLE hLobbyLaunchedConnection = NULL;
  457.     HRESULT hr;
  458.  
  459.     // Create IDirectPlay8Peer
  460.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL, 
  461.                                        CLSCTX_INPROC_SERVER,
  462.                                        IID_IDirectPlay8Peer, 
  463.                                        (LPVOID*) &m_pDP ) ) )
  464.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  465.  
  466.     // Create IDirectPlay8LobbiedApplication
  467.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8LobbiedApplication, NULL, 
  468.                                        CLSCTX_INPROC_SERVER,
  469.                                        IID_IDirectPlay8LobbiedApplication, 
  470.                                        (LPVOID*) &m_pLobbiedApp ) ) )
  471.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  472.  
  473.     // Init the helper class, now that m_pDP and m_pLobbiedApp are valid
  474.     m_pNetConnectWizard->Init( m_pDP, m_pLobbiedApp );
  475.  
  476.     // Init IDirectPlay8Peer
  477.     if( FAILED( hr = m_pDP->Initialize( NULL, StaticDirectPlayMessageHandler, 0 ) ) )
  478.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  479.  
  480.     // Init IDirectPlay8LobbiedApplication.  Before this Initialize() returns 
  481.     // a DPL_MSGID_CONNECT msg may come in to the DirectPlayLobbyMessageHandler 
  482.     // so be prepared ahead of time.
  483.     if( FAILED( hr = m_pLobbiedApp->Initialize( NULL, StaticDirectPlayLobbyMessageHandler, 
  484.                                                 &hLobbyLaunchedConnection, 0 ) ) )
  485.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  486.  
  487.     // IDirectPlay8LobbiedApplication::Initialize returns a handle to a connection
  488.     // if we have been lobby launched.  Initialize is guaranteed to return after 
  489.     // the DPL_MSGID_CONNECT msg has been processed.  So unless a we are expected 
  490.     // multiple lobby connections, we do not need to remember the lobby connection
  491.     // handle since it will be recorded upon the DPL_MSGID_CONNECT msg.
  492.     m_bWasLobbyLaunched = ( hLobbyLaunchedConnection != NULL );
  493.  
  494.         return S_OK;
  495. }
  496.  
  497.  
  498.  
  499.  
  500. //-----------------------------------------------------------------------------
  501. // Name: ConnectViaDirectPlay()
  502. // Desc: Create a new DirectPlay session or join to an existing DirectPlay session
  503. //-----------------------------------------------------------------------------
  504. HRESULT CAppForm::ConnectViaDirectPlay()
  505. {
  506.     HRESULT hr;
  507.     BOOL bWasFullscreen  = FALSE;
  508.     BOOL bConnectSuccess = FALSE;
  509.  
  510.     // Can't display dialogs in fullscreen mode
  511.     if( m_bWindowed == FALSE )
  512.     {
  513.         bWasFullscreen = TRUE;
  514.  
  515.         if( FAILED( ToggleFullscreen() ) )
  516.         {
  517.             DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  518.             return E_FAIL;
  519.         }
  520.     }
  521.  
  522.     // If we were launched from a lobby client, then we may have connection settings
  523.     // that we can use either host or join a game.  If not, then we'll need to prompt 
  524.     // the user to determine how to connect.
  525.     if( m_bWasLobbyLaunched && m_pNetConnectWizard->HaveConnectionSettingsFromLobby() )
  526.     {
  527.         // If were lobby launched then the DPL_MSGID_CONNECT has already been
  528.         // handled, and since the lobby client also sent us connection settings
  529.         // we can use them to either host or join a DirectPlay session. 
  530.         if( FAILED( hr = m_pNetConnectWizard->ConnectUsingLobbySettings() ) )
  531.         {
  532.             DXTRACE_ERR( TEXT("ConnectUsingLobbySettings"), hr );
  533.             MessageBox( TEXT("Failed to connect using lobby settings. ")
  534.                         TEXT("The sample will now quit."),
  535.                         TEXT("$$root$$"), MB_OK | MB_ICONERROR );
  536.  
  537.             bConnectSuccess = FALSE;
  538.         }
  539.         else
  540.         {
  541.             // Read information from m_pNetConnectWizard
  542.             _tcscpy( m_strLocalPlayerName, m_pNetConnectWizard->GetPlayerName() );
  543.  
  544.             bConnectSuccess = TRUE; 
  545.         }
  546.     }
  547.     else
  548.     {
  549.         // If not lobby launched, prompt the user about the network 
  550.         // connection and which session they would like to join or 
  551.         // if they want to create a new one.
  552.  
  553.         // Setup connection wizard
  554.         m_pNetConnectWizard->SetPlayerName( m_strLocalPlayerName );
  555.         m_pNetConnectWizard->SetSessionName( m_strSessionName );
  556.         m_pNetConnectWizard->SetPreferredProvider( m_strPreferredProvider );
  557.  
  558.         // Start a connection wizard.  The wizard uses GDI dialog boxes.
  559.         // More complex games can use this as a starting point and add a 
  560.         // fancier graphics layer such as Direct3D.
  561.         hr = m_pNetConnectWizard->DoConnectWizard( FALSE );        
  562.         if( FAILED( hr ) ) 
  563.         {
  564.             DXTRACE_ERR( TEXT("DoConnectWizard"), hr );
  565.             MessageBox( TEXT("Multiplayer connect failed. ")
  566.                         TEXT("The sample will now quit."),
  567.                         TEXT("$$root$$"), MB_OK | MB_ICONERROR );
  568.             bConnectSuccess = FALSE;
  569.         } 
  570.         else if( hr == NCW_S_QUIT ) 
  571.         {
  572.             // The user canceled the Multiplayer connect
  573.             bConnectSuccess = FALSE;
  574.         }
  575.         else
  576.         {
  577.             bConnectSuccess = TRUE; 
  578.  
  579.             // Read information from m_pNetConnectWizard
  580.             _tcscpy( m_strLocalPlayerName, m_pNetConnectWizard->GetPlayerName() );
  581.             _tcscpy( m_strSessionName, m_pNetConnectWizard->GetSessionName() );
  582.             _tcscpy( m_strPreferredProvider, m_pNetConnectWizard->GetPreferredProvider() );
  583.  
  584.             // Write information to the registry
  585.             WriteSettings();
  586.         }
  587.     }
  588.  
  589. $$IF(DPLAYVOICE)
  590.     if( bConnectSuccess )
  591.     {
  592.         // Initialize DirectPlay voice
  593.         if( FAILED( hr = InitDirectPlayVoice() ) )
  594.         {
  595.             bConnectSuccess = FALSE;
  596.  
  597.             if( hr == DVERR_USERBACK )
  598.             {
  599.                 MessageBox( TEXT("The user backed out of the wizard.  ")
  600.                             TEXT("This simple sample does not handle this case, so ")
  601.                             TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  602.             }
  603.             else if( hr == DVERR_USERCANCEL )
  604.             {
  605.                 MessageBox( TEXT("The user canceled the wizard. ")
  606.                             TEXT("This simple sample does not handle this case, so ")
  607.                             TEXT("the sample will quit."), TEXT("DirectPlay Sample"), MB_OK );
  608.             }
  609.             else 
  610.             {
  611.                 DXTRACE_ERR( TEXT("m_pNetVoice->Init"), hr );
  612.             }
  613.         }
  614.  
  615.         if( m_pNetVoice->IsHalfDuplex() ) 
  616.         {
  617.             MessageBox( TEXT("You are running in half duplex mode. ")
  618.                         TEXT("In half duplex mode no recording takes place."), 
  619.                         TEXT("blank"), MB_OK );
  620.         }
  621.     }
  622.  
  623. $$ENDIF
  624.     if( FALSE == bConnectSuccess )
  625.     {
  626.         // Quit the app
  627.         PostQuitMessage(0);
  628.     }
  629.     else
  630.     {
  631.         // Return to fullscreen mode after dialogs
  632.         if( bWasFullscreen )
  633.         {
  634.             if( FAILED( ToggleFullscreen() ) )
  635.             {
  636.                 DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  637.                 return E_FAIL;
  638.             }
  639.         }
  640.     }
  641.  
  642.     return S_OK;
  643. }
  644.  
  645.  
  646.  
  647.  
  648. $$ENDIF
  649. $$IF(DPLAYVOICE)
  650. //-----------------------------------------------------------------------------
  651. // Name: InitDirectPlayVoice()
  652. // Desc: Init DirectPlay Voice
  653. //-----------------------------------------------------------------------------
  654. HRESULT CAppForm::InitDirectPlayVoice()
  655. {
  656.     HRESULT hr;
  657.  
  658.     // Set default DirectPlayVoice setup options
  659.     // TODO: change as needed or ask user for settings
  660.     ZeroMemory( &m_dvClientConfig, sizeof(m_dvClientConfig) );
  661.     m_dvClientConfig.dwSize                 = sizeof(m_dvClientConfig);
  662.     m_dvClientConfig.dwFlags                = DVCLIENTCONFIG_AUTOVOICEACTIVATED |
  663.                                               DVCLIENTCONFIG_AUTORECORDVOLUME;
  664.     m_dvClientConfig.lPlaybackVolume        = DVPLAYBACKVOLUME_DEFAULT;
  665.     m_dvClientConfig.dwBufferQuality        = DVBUFFERQUALITY_DEFAULT;
  666.     m_dvClientConfig.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  667.     m_dvClientConfig.dwThreshold            = DVTHRESHOLD_UNUSED;
  668.     m_dvClientConfig.lRecordVolume          = DVRECORDVOLUME_LAST;
  669.     m_dvClientConfig.dwNotifyPeriod         = 0;
  670.  
  671.     m_guidDVSessionCT                       = DPVCTGUID_DEFAULT;
  672.  
  673.     // Creates and connects to DirectPlay Voice using the settings stored 
  674.     // in m_guidDVSessionCT & m_dvClientConfig.  It also runs the DirectPlay
  675.     // Voice wizard if it hasn't been run before on this machine
  676.     if( FAILED( hr = m_pNetVoice->Init( m_hWndTopLevelParent, m_pNetConnectWizard->IsHostPlayer(), TRUE,
  677.                                         m_pDP, DVSESSIONTYPE_PEER, 
  678.                                         &m_guidDVSessionCT, &m_dvClientConfig ) ) )
  679.         return hr;
  680.  
  681.     return S_OK;
  682. }
  683.  
  684.  
  685.  
  686.  
  687. $$ENDIF
  688. //-----------------------------------------------------------------------------
  689. // Name: ConfirmDevice()
  690. // Desc: Called during device initialization, this code checks the display device
  691. //       for some minimum set of capabilities
  692. //-----------------------------------------------------------------------------
  693. HRESULT CAppForm::ConfirmDevice( D3DCAPS8* pCaps, DWORD dwBehavior,
  694.                                           D3DFORMAT Format )
  695. {
  696.     BOOL bCapsAcceptable;
  697.  
  698.     // TODO: Perform checks to see if these display caps are acceptable.
  699.     bCapsAcceptable = TRUE;
  700.  
  701.     if( bCapsAcceptable )         
  702.         return S_OK;
  703.     else
  704.         return E_FAIL;
  705. }
  706.  
  707.  
  708.  
  709.  
  710. //-----------------------------------------------------------------------------
  711. // Name: CAppForm::InitDeviceObjects()
  712. // Desc: Initialize scene objects.
  713. //-----------------------------------------------------------------------------
  714. HRESULT CAppForm::InitDeviceObjects()
  715. {
  716.     // TODO: create device objects
  717.  
  718. $$IF(SHOW_TRIANGLE || SHOW_TEAPOT)
  719.     HRESULT hr;
  720.  
  721. $$ENDIF
  722. $$IF(D3DFONT)
  723.     // Init the font
  724.     m_pFont->InitDeviceObjects( m_pd3dDevice );
  725.  
  726. $$ENDIF
  727. $$IF(SHOW_TRIANGLE)
  728.     // Create the vertex buffer
  729.     if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( 3*2*sizeof(CUSTOMVERTEX),
  730.                                                   0, D3DFVF_CUSTOMVERTEX,
  731.                                                   D3DPOOL_MANAGED, &m_pVB ) ) )
  732.         return DXTRACE_ERR_NOMSGBOX( "CreateVertexBuffer", hr );
  733.  
  734.     // Fill the vertex buffer with 2 triangles
  735.     CUSTOMVERTEX* pVertices;
  736.  
  737.     if( FAILED( hr = m_pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 ) ) )
  738.         return DXTRACE_ERR_NOMSGBOX( "Lock", hr );
  739.  
  740.     // Front triangle
  741.     pVertices[0].position = D3DXVECTOR3( -1.0f, -1.0f,  0.0f );
  742.     pVertices[0].normal   = D3DXVECTOR3(  0.0f,  0.0f, -1.0f );
  743.     pVertices[1].position = D3DXVECTOR3(  0.0f,  1.0f,  0.0f );
  744.     pVertices[1].normal   = D3DXVECTOR3(  0.0f,  0.0f, -1.0f );
  745.     pVertices[2].position = D3DXVECTOR3(  1.0f, -1.0f,  0.0f );
  746.     pVertices[2].normal   = D3DXVECTOR3(  0.0f,  0.0f, -1.0f );
  747.  
  748.     // Back triangle
  749.     pVertices[3].position = D3DXVECTOR3( -1.0f, -1.0f,  0.0f );
  750.     pVertices[3].normal   = D3DXVECTOR3(  0.0f,  0.0f,  1.0f );
  751.     pVertices[4].position = D3DXVECTOR3(  1.0f, -1.0f,  0.0f );
  752.     pVertices[4].normal   = D3DXVECTOR3(  0.0f,  0.0f,  1.0f );
  753.     pVertices[5].position = D3DXVECTOR3(  0.0f,  1.0f,  0.0f );
  754.     pVertices[5].normal   = D3DXVECTOR3(  0.0f,  0.0f,  1.0f );
  755.  
  756.     m_pVB->Unlock();
  757.  
  758. $$ENDIF
  759. $$IF(SHOW_TEAPOT)
  760.     // Create a teapot mesh using D3DX
  761.     if( FAILED( hr = D3DXCreateTeapot( m_pd3dDevice, &m_pD3DXMesh, NULL ) ) )
  762.         return DXTRACE_ERR_NOMSGBOX( "D3DXCreateTeapot", hr );
  763.  
  764. $$ENDIF
  765.     return S_OK;
  766. }
  767.  
  768.  
  769.  
  770.  
  771. //-----------------------------------------------------------------------------
  772. // Name: CAppForm::RestoreDeviceObjects()
  773. // Desc: Initialize scene objects.
  774. //-----------------------------------------------------------------------------
  775. HRESULT CAppForm::RestoreDeviceObjects()
  776. {
  777.     // TODO: setup render states
  778. $$IF(!D3DFONT || ACTIONMAPPER)
  779.     HRESULT hr;
  780. $$ENDIF
  781.  
  782.     // Setup a material
  783.     D3DMATERIAL8 mtrl;
  784.     D3DUtil_InitMaterial( mtrl, 1.0f, 0.0f, 0.0f );
  785.     m_pd3dDevice->SetMaterial( &mtrl );
  786.  
  787.     // Set up the textures
  788.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  789.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  790.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  791.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  792.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  793.  
  794.     // Set miscellaneous render states
  795.     m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE,   FALSE );
  796.     m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, FALSE );
  797.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,        TRUE );
  798.     m_pd3dDevice->SetRenderState( D3DRS_AMBIENT,        0x000F0F0F );
  799.  
  800.     // Set the world matrix
  801.     D3DXMATRIX matIdentity;
  802.     D3DXMatrixIdentity( &matIdentity );
  803.     m_pd3dDevice->SetTransform( D3DTS_WORLD,  &matIdentity );
  804.  
  805.     // Set up our view matrix. A view matrix can be defined given an eye point,
  806.     // a point to lookat, and a direction for which way is up. Here, we set the
  807.     // eye five units back along the z-axis and up three units, look at the
  808.     // origin, and define "up" to be in the y-direction.
  809.     D3DXMATRIX matView;
  810.     D3DXVECTOR3 vFromPt   = D3DXVECTOR3( 0.0f, 0.0f, -5.0f );
  811.     D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  812.     D3DXVECTOR3 vUpVec    = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  813.     D3DXMatrixLookAtLH( &matView, &vFromPt, &vLookatPt, &vUpVec );
  814.     m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
  815.  
  816.     // Set the projection matrix
  817.     D3DXMATRIX matProj;
  818.     FLOAT fAspect = ((FLOAT)m_d3dsdBackBuffer.Width) / m_d3dsdBackBuffer.Height;
  819.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 1.0f, 100.0f );
  820.     m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  821.  
  822.     // Set up lighting states
  823.     D3DLIGHT8 light;
  824.     D3DUtil_InitLight( light, D3DLIGHT_DIRECTIONAL, -1.0f, -1.0f, 2.0f );
  825.     m_pd3dDevice->SetLight( 0, &light );
  826.     m_pd3dDevice->LightEnable( 0, TRUE );
  827.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  828.  
  829. $$IF(D3DFONT)
  830.     // Restore the font
  831.     m_pFont->RestoreDeviceObjects();
  832. $$ELSE
  833.     // Create a D3D font using D3DX
  834.     HFONT hFont = CreateFont( 20, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
  835.                               ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  836.                               ANTIALIASED_QUALITY, FF_DONTCARE, "Arial" );      
  837.     if( FAILED( hr = D3DXCreateFont( m_pd3dDevice, hFont, &m_pD3DXFont ) ) )
  838.         return DXTRACE_ERR_NOMSGBOX( "D3DXCreateFont", hr );
  839. $$ENDIF
  840. $$IF(ACTIONMAPPER)
  841.  
  842.     if( !m_bWindowed )
  843.     {
  844.         // Create a surface for configuring DInput devices
  845.         if( FAILED( hr = m_pd3dDevice->CreateImageSurface( 640, 480, 
  846.                                         m_d3dsdBackBuffer.Format, &m_pDIConfigSurface ) ) ) 
  847.             return DXTRACE_ERR_NOMSGBOX( "CreateImageSurface", hr );
  848.     }
  849. $$ENDIF
  850.  
  851.     return S_OK;
  852. }
  853.  
  854.  
  855.  
  856.  
  857. $$IF(ACTIONMAPPER)
  858. //-----------------------------------------------------------------------------
  859. // Name: StaticConfigureInputDevicesCB()
  860. // Desc: Static callback helper to call into CAppForm class
  861. //-----------------------------------------------------------------------------
  862. BOOL CALLBACK CAppForm::StaticConfigureInputDevicesCB( 
  863.                                             IUnknown* pUnknown, VOID* pUserData )
  864. {
  865.     CAppForm* pApp = (CAppForm*) pUserData;
  866.     return pApp->ConfigureInputDevicesCB( pUnknown );
  867. }
  868.  
  869.  
  870.  
  871.  
  872. //-----------------------------------------------------------------------------
  873. // Name: ConfigureInputDevicesCB()
  874. // Desc: Callback function for configuring input devices. This function is
  875. //       called in fullscreen modes, so that the input device configuration
  876. //       window can update the screen.
  877. //-----------------------------------------------------------------------------
  878. BOOL CAppForm::ConfigureInputDevicesCB( IUnknown* pUnknown )
  879. {
  880.     // Get access to the surface
  881.     LPDIRECT3DSURFACE8 pConfigSurface = NULL;
  882.     if( FAILED( pUnknown->QueryInterface( IID_IDirect3DSurface8,
  883.                                           (VOID**)&pConfigSurface ) ) )
  884.         return TRUE;
  885.  
  886.     // Render the scene, with the config surface blitted on top
  887.     Render();
  888.  
  889.     RECT  rcSrc;
  890.     SetRect( &rcSrc, 0, 0, 640, 480 );
  891.  
  892.     POINT ptDst;
  893.     ptDst.x = (m_d3dsdBackBuffer.Width-640)/2;
  894.     ptDst.y = (m_d3dsdBackBuffer.Height-480)/2;
  895.  
  896.     LPDIRECT3DSURFACE8 pBackBuffer;
  897.     m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  898.     m_pd3dDevice->CopyRects( pConfigSurface, &rcSrc, 1, pBackBuffer, &ptDst );
  899.     pBackBuffer->Release();
  900.  
  901.     // Present the backbuffer contents to the front buffer
  902.     m_pd3dDevice->Present( 0, 0, 0, 0 );
  903.  
  904.     // Release the surface
  905.     pConfigSurface->Release();
  906.  
  907.     return TRUE;
  908. }
  909.  
  910.  
  911.  
  912.  
  913. $$ENDIF
  914. //-----------------------------------------------------------------------------
  915. // Name: CAppForm::FrameMove()
  916. // Desc: Called once per frame, the call is the entry point for animating
  917. //       the scene.
  918. //-----------------------------------------------------------------------------
  919. HRESULT CAppForm::FrameMove()
  920. {
  921.     // TODO: update world
  922.  
  923.     // Update user input state
  924.     UpdateInput( &m_UserInput );
  925.  
  926. $$IF(DPLAY)
  927.     // Send local input to all network players if it changed
  928.     SendLocalInputIfChanged();
  929.  
  930.     if( m_pNetConnectWizard->IsHostPlayer() )
  931.     {
  932.         m_fWorldSyncTimer -= m_fElapsedTime;
  933.         if( m_fWorldSyncTimer < 0.0f )
  934.         {
  935.             // If this player is the host and timer has expired
  936.             // then reset timer and send the world state to all players
  937.             m_fWorldSyncTimer = 0.1f;
  938.             SendWorldStateToAll();
  939.         }
  940.     }
  941.  
  942. $$ENDIF
  943. $$IF(ACTIONMAPPER)
  944.     // Respond to input
  945.     if( m_UserInput.bDoConfigureInput )
  946.     {
  947.         // One-shot per keypress
  948.         m_UserInput.bDoConfigureInput = FALSE;
  949.  
  950.         Pause( TRUE );
  951.  
  952.         // Get access to the list of semantically-mapped input devices
  953.         // to delete all InputDeviceState structs before calling ConfigureDevices()
  954.         CInputDeviceManager::DeviceInfo* pDeviceInfos;
  955.         DWORD dwNumDevices;
  956.         m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  957.  
  958.         for( DWORD i=0; i<dwNumDevices; i++ )
  959.         {
  960.             InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  961.             SAFE_DELETE( pInputDeviceState );
  962.             pDeviceInfos[i].pParam = NULL;
  963.         }
  964.  
  965.         // Configure the devices (with edit capability)
  966.         if( m_bWindowed )
  967.             m_pInputDeviceManager->ConfigureDevices( m_hWndTopLevelParent, NULL, NULL, DICD_EDIT, NULL );
  968.         else
  969.             m_pInputDeviceManager->ConfigureDevices( m_hwndRenderFullScreen,
  970.                                                      m_pDIConfigSurface,
  971.                                                      (VOID*)StaticConfigureInputDevicesCB,
  972.                                                      DICD_EDIT, (LPVOID) this );
  973.  
  974.         Pause( FALSE );
  975.     }
  976.  
  977.     if( m_UserInput.bDoConfigureDisplay )
  978.     {
  979.         // One-shot per keypress
  980.         m_UserInput.bDoConfigureDisplay = FALSE;
  981.  
  982.         OnChangeDevice();
  983.     }
  984.  
  985. $$ENDIF
  986. $$IF(DPLAYVOICE)
  987.     if( m_UserInput.bDoConfigureVoice )
  988.     {
  989.         // One-shot per keypress
  990.         m_UserInput.bDoConfigureVoice = FALSE;
  991.  
  992.         Pause(TRUE);
  993.  
  994.         // Allow user to configure the voice settings
  995.         UserConfigVoice();
  996.  
  997.         Pause(FALSE);
  998.     }
  999.  
  1000. $$ENDIF
  1001. $$IF(DPLAY)
  1002.     // Combining the input data from all players 
  1003.     // TODO: Combining the input data from all players is an unrealistic yet simple 
  1004.     //       usage of network data. Use it as a starting point to serve your needs
  1005.     CombineInputFromAllPlayers( &m_CombinedNetworkInput );
  1006.  
  1007. $$ENDIF
  1008. $$IF(DPLAYVOICE)
  1009.     // Update talking variables
  1010.     // TODO: The talking variables just update the text, but something more complex
  1011.     //       like animation could be done based on them
  1012.     UpdateTalkingVariables();
  1013.  
  1014. $$ENDIF
  1015.     // Update the world state according to user input
  1016.     D3DXMATRIX matWorld;
  1017.     D3DXMATRIX matRotY;
  1018.     D3DXMATRIX matRotX;
  1019.  
  1020. $$IF(DPLAY)
  1021.     // Enter world state critical section before accessing world state data 
  1022.     // otherwise one of the DirectPlay threads may change the data
  1023.     // while this thread is accessing or changing it.
  1024.     WORLD_LOCK();
  1025.  
  1026.     // Rotate object according to user input from all network players
  1027.     // Only update the world state if the host hasn't told our to pause
  1028.     if( FALSE == m_bHostPausing )
  1029.     {
  1030.         // Update the m_fWorldRotY & m_fWorldRotX according 
  1031.         // to the combined input of all the network players
  1032. $$IF(ACTIONMAPPER)
  1033.         if( m_CombinedNetworkInput.fAxisRotateLR )
  1034.             m_fWorldRotY += m_fElapsedTime * m_CombinedNetworkInput.fAxisRotateLR;
  1035.  
  1036.         if( m_CombinedNetworkInput.fAxisRotateUD )
  1037.             m_fWorldRotX += m_fElapsedTime * m_CombinedNetworkInput.fAxisRotateUD;
  1038. $$ELSE // start !ACTIONMAPPER
  1039.         if( m_CombinedNetworkInput.bRotateLeft && !m_CombinedNetworkInput.bRotateRight )
  1040.             m_fWorldRotY += m_fElapsedTime;
  1041.         else if( m_CombinedNetworkInput.bRotateRight && !m_CombinedNetworkInput.bRotateLeft )
  1042.             m_fWorldRotY -= m_fElapsedTime;
  1043.  
  1044.         if( m_CombinedNetworkInput.bRotateUp && !m_CombinedNetworkInput.bRotateDown )
  1045.             m_fWorldRotX += m_fElapsedTime;
  1046.         else if( m_CombinedNetworkInput.bRotateDown && !m_CombinedNetworkInput.bRotateUp )
  1047.             m_fWorldRotX -= m_fElapsedTime;
  1048. $$ENDIF // end ACTIONMAPPER
  1049.     }
  1050.  
  1051.     // Calculate and update the world matrix
  1052.     D3DXMatrixRotationX( &matRotX, m_fWorldRotX );
  1053.     D3DXMatrixRotationY( &matRotY, m_fWorldRotY );
  1054.  
  1055.     // Leave the critical section
  1056.     WORLD_UNLOCK();
  1057.  
  1058. $$ENDIF // end DPLAY
  1059. $$IF(!DPLAY)
  1060. $$IF(ACTIONMAPPER)
  1061.     if( m_UserInput.fAxisRotateLR )
  1062.         m_fWorldRotY += m_fElapsedTime * m_UserInput.fAxisRotateLR;
  1063.  
  1064.     if( m_UserInput.fAxisRotateUD )
  1065.         m_fWorldRotX += m_fElapsedTime * m_UserInput.fAxisRotateUD;
  1066.  
  1067. $$ELSE // start !ACTIONMAPPER
  1068.     if( m_UserInput.bRotateLeft && !m_UserInput.bRotateRight )
  1069.         m_fWorldRotY += m_fElapsedTime;
  1070.     else if( m_UserInput.bRotateRight && !m_UserInput.bRotateLeft )
  1071.         m_fWorldRotY -= m_fElapsedTime;
  1072.  
  1073.     if( m_UserInput.bRotateUp && !m_UserInput.bRotateDown )
  1074.         m_fWorldRotX += m_fElapsedTime;
  1075.     else if( m_UserInput.bRotateDown && !m_UserInput.bRotateUp )
  1076.         m_fWorldRotX -= m_fElapsedTime;
  1077.  
  1078. $$ENDIF // end ACTIONMAPPER
  1079.     D3DXMatrixRotationX( &matRotX, m_fWorldRotX );
  1080.     D3DXMatrixRotationY( &matRotY, m_fWorldRotY );
  1081.  
  1082. $$ENDIF // end !DPLAY
  1083.     D3DXMatrixMultiply( &matWorld, &matRotX, &matRotY );
  1084.     m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  1085.  
  1086. $$IF(DMUSIC || DSOUND)
  1087.     // Play the sound every so often while the button is pressed 
  1088.     if( m_UserInput.bPlaySoundButtonDown )
  1089.     {
  1090.         m_fSoundPlayRepeatCountdown -= m_fElapsedTime;
  1091.         if( m_fSoundPlayRepeatCountdown <= 0.0f )
  1092.         {
  1093.             m_fSoundPlayRepeatCountdown = 0.5f;
  1094.             if( m_pBounceSound )
  1095.                 m_pBounceSound->Play();
  1096.         }
  1097.     }
  1098.     else
  1099.     {
  1100.         m_fSoundPlayRepeatCountdown = 0.0f;
  1101.     }
  1102.  
  1103. $$ENDIF
  1104.     return S_OK;
  1105. }
  1106.  
  1107.  
  1108.  
  1109.  
  1110. //-----------------------------------------------------------------------------
  1111. // Name: UpdateInput()
  1112. // Desc: Update the user input.  Called once per frame 
  1113. //-----------------------------------------------------------------------------
  1114. void CAppForm::UpdateInput( UserInput* pUserInput )
  1115. {
  1116. $$IF(ACTIONMAPPER)
  1117.     if( NULL == m_pInputDeviceManager )
  1118.         return;
  1119.  
  1120.     // Get access to the list of semantically-mapped input devices
  1121.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  1122.     DWORD dwNumDevices;
  1123.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  1124.  
  1125.     // Loop through all devices and check game input
  1126.     for( DWORD i=0; i<dwNumDevices; i++ )
  1127.     {
  1128.         DIDEVICEOBJECTDATA rgdod[10];
  1129.         DWORD   dwItems = 10;
  1130.         HRESULT hr;
  1131.         LPDIRECTINPUTDEVICE8 pdidDevice = pDeviceInfos[i].pdidDevice;
  1132.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  1133.  
  1134.         hr = pdidDevice->Acquire();
  1135.         hr = pdidDevice->Poll();
  1136.         hr = pdidDevice->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
  1137.                                         rgdod, &dwItems, 0 );
  1138.         if( FAILED(hr) )
  1139.             continue;
  1140.  
  1141.         // Get the sematics codes for the game menu
  1142.         for( DWORD j=0; j<dwItems; j++ )
  1143.         {
  1144.             BOOL  bButtonState = (rgdod[j].dwData==0x80) ? TRUE : FALSE;
  1145.             FLOAT fButtonState = (rgdod[j].dwData==0x80) ? 1.0f : 0.0f;
  1146.             FLOAT fAxisState   = (FLOAT)((int)rgdod[j].dwData)/100.0f;
  1147.  
  1148.             switch( rgdod[j].uAppData )
  1149.             {
  1150.                 // TODO: Handle semantics for the game 
  1151.  
  1152.                 // Handle relative axis data
  1153.                 case INPUT_ROTATE_AXIS_LR: 
  1154.                     pInputDeviceState->fAxisRotateLR = -fAxisState;
  1155.                     break;
  1156.                 case INPUT_ROTATE_AXIS_UD:
  1157.                     pInputDeviceState->fAxisRotateUD = -fAxisState;
  1158.                     break;
  1159.  
  1160.                 // Handle buttons separately so the button state data
  1161.                 // doesn't overwrite the axis state data, and handle
  1162.                 // each button separately so they don't overwrite each other
  1163.                 case INPUT_ROTATE_LEFT:  pInputDeviceState->bButtonRotateLeft  = bButtonState; break;
  1164.                 case INPUT_ROTATE_RIGHT: pInputDeviceState->bButtonRotateRight = bButtonState; break;
  1165.                 case INPUT_ROTATE_UP:    pInputDeviceState->bButtonRotateUp    = bButtonState; break;
  1166.                 case INPUT_ROTATE_DOWN:  pInputDeviceState->bButtonRotateDown  = bButtonState; break;
  1167. $$IF(DMUSIC || DSOUND)
  1168.                 case INPUT_PLAY_SOUND:   pInputDeviceState->bButtonPlaySoundButtonDown = bButtonState; break;
  1169. $$ENDIF // DMUSIC || DSOUND
  1170.  
  1171.                 // Handle one-shot buttons
  1172.                 case INPUT_CONFIG_INPUT:   if( bButtonState ) pUserInput->bDoConfigureInput = TRUE; break;
  1173.                 case INPUT_CONFIG_DISPLAY: if( bButtonState ) pUserInput->bDoConfigureDisplay = TRUE; break;
  1174. $$IF(DPLAYVOICE)
  1175.                 case INPUT_CONFIG_VOICE:   if( bButtonState ) pUserInput->bDoConfigureVoice   = TRUE; break;
  1176. $$ENDIF
  1177.             }
  1178.         }
  1179.     }
  1180.  
  1181.     // TODO: change process code as needed
  1182.  
  1183.     // Process user input and store result into pUserInput struct
  1184.     pUserInput->fAxisRotateLR = 0.0f;
  1185.     pUserInput->fAxisRotateUD = 0.0f;
  1186. $$IF(DMUSIC || DSOUND)
  1187.     pUserInput->bPlaySoundButtonDown = FALSE;
  1188. $$ENDIF
  1189.  
  1190.     // Concatinate the data from all the DirectInput devices
  1191.     for( i=0; i<dwNumDevices; i++ )
  1192.     {
  1193.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  1194.  
  1195.         // Use the axis data that is furthest from zero
  1196.         if( fabs(pInputDeviceState->fAxisRotateLR) > fabs(pUserInput->fAxisRotateLR) )
  1197.             pUserInput->fAxisRotateLR = pInputDeviceState->fAxisRotateLR;
  1198.  
  1199.         if( fabs(pInputDeviceState->fAxisRotateUD) > fabs(pUserInput->fAxisRotateUD) )
  1200.             pUserInput->fAxisRotateUD = pInputDeviceState->fAxisRotateUD;
  1201.  
  1202.         // Process the button data 
  1203.         if( pInputDeviceState->bButtonRotateLeft )
  1204.             pUserInput->fAxisRotateLR = 1.0f;
  1205.         else if( pInputDeviceState->bButtonRotateRight )
  1206.             pUserInput->fAxisRotateLR = -1.0f;
  1207.  
  1208.         if( pInputDeviceState->bButtonRotateUp )
  1209.             pUserInput->fAxisRotateUD = 1.0f;
  1210.         else if( pInputDeviceState->bButtonRotateDown )
  1211.             pUserInput->fAxisRotateUD = -1.0f;
  1212.  
  1213. $$IF(DMUSIC || DSOUND)
  1214.         if( pInputDeviceState->bButtonPlaySoundButtonDown )
  1215.             pUserInput->bPlaySoundButtonDown = TRUE;
  1216. $$ENDIF // DMUSIC || DSOUND
  1217.     } 
  1218. $$ENDIF // ACTIONMAPPER
  1219. $$IF(KEYBOARD)
  1220.     HRESULT hr;
  1221.  
  1222.     // Get the input's device state, and put the state in dims
  1223.     ZeroMemory( &pUserInput->diks, sizeof(pUserInput->diks) );
  1224.     hr = m_pKeyboard->GetDeviceState( sizeof(pUserInput->diks), &pUserInput->diks );
  1225.     if( FAILED(hr) ) 
  1226.     {
  1227.         m_pKeyboard->Acquire();
  1228.         return; 
  1229.     }
  1230.  
  1231.     // TODO: Process user input as needed
  1232.     pUserInput->bRotateLeft  = ( (pUserInput->diks[DIK_LEFT] & 0x80)  == 0x80 );
  1233.     pUserInput->bRotateRight = ( (pUserInput->diks[DIK_RIGHT] & 0x80) == 0x80 );
  1234.     pUserInput->bRotateUp    = ( (pUserInput->diks[DIK_UP] & 0x80)    == 0x80 );
  1235.     pUserInput->bRotateDown  = ( (pUserInput->diks[DIK_DOWN] & 0x80)  == 0x80 );
  1236. $$IF(DMUSIC || DSOUND)
  1237.     pUserInput->bPlaySoundButtonDown   = ( (pUserInput->diks[DIK_F5] & 0x80)     == 0x80 );
  1238. $$ENDIF // DMUSIC || DSOUND
  1239. $$ENDIF // KEYBOARD
  1240. $$IF(!DINPUT)
  1241.     m_bHasFocus = ( m_hWndTopLevelParent == GetForegroundWindow()->GetSafeHwnd() );
  1242.     pUserInput->bRotateUp    = ( m_bHasFocus && (GetAsyncKeyState( VK_UP )    & 0x8000) == 0x8000 );
  1243.     pUserInput->bRotateDown  = ( m_bHasFocus && (GetAsyncKeyState( VK_DOWN )  & 0x8000) == 0x8000 );
  1244.     pUserInput->bRotateLeft  = ( m_bHasFocus && (GetAsyncKeyState( VK_LEFT )  & 0x8000) == 0x8000 );
  1245.     pUserInput->bRotateRight = ( m_bHasFocus && (GetAsyncKeyState( VK_RIGHT ) & 0x8000) == 0x8000 );
  1246. $$IF(DMUSIC || DSOUND)
  1247.     pUserInput->bPlaySoundButtonDown = ( m_bHasFocus && (GetAsyncKeyState( VK_F5 ) & 0x8000) == 0x8000 );
  1248. $$ENDIF // DMUSIC || DSOUND
  1249. $$ENDIF // !DINPUT
  1250. }
  1251.  
  1252.  
  1253.  
  1254.  
  1255. $$IF(DPLAY)
  1256. //-----------------------------------------------------------------------------
  1257. // Name: SendLocalInputIfChanged()
  1258. // Desc: Send local input to all network players if it changed
  1259. //-----------------------------------------------------------------------------
  1260. HRESULT CAppForm::SendLocalInputIfChanged()
  1261. {
  1262.     if( NULL == m_pLocalPlayerInfo )
  1263.         return S_OK;
  1264.  
  1265.     // Enter player critical section before accessing player's state data 
  1266.     // otherwise the DirectPlay network threads may change the data
  1267.     // while this thread is accessing it.
  1268.     PLAYER_LOCK();                  
  1269.  
  1270.     // Compare the local input axis data from DirectInput against the 
  1271.     // state of the axis data stored in the local player's 
  1272.     // APP_PLAYER_INFO struct to see if input changed
  1273.     BOOL bLocalInputChanged = FALSE;
  1274. $$IF(ACTIONMAPPER)
  1275.     if( m_UserInput.fAxisRotateLR != m_pLocalPlayerInfo->fAxisRotateLR ||
  1276.         m_UserInput.fAxisRotateUD != m_pLocalPlayerInfo->fAxisRotateUD )
  1277. $$ELSE
  1278.     if( m_UserInput.bRotateUp    != m_pLocalPlayerInfo->bRotateUp   ||
  1279.         m_UserInput.bRotateDown  != m_pLocalPlayerInfo->bRotateDown ||
  1280.         m_UserInput.bRotateLeft  != m_pLocalPlayerInfo->bRotateLeft ||
  1281.         m_UserInput.bRotateRight != m_pLocalPlayerInfo->bRotateRight )
  1282. $$ENDIF
  1283.     {
  1284.         bLocalInputChanged = TRUE;
  1285.     }
  1286.  
  1287.     PLAYER_UNLOCK();                // leave player context CS
  1288.  
  1289.     // If it has changed then send it to all the network players
  1290.     // including the local player
  1291.     if( bLocalInputChanged )
  1292.     {
  1293.         GAMEMSG_INPUTSTATE msgInputState;
  1294.         msgInputState.nType = GAME_MSGID_INPUTSTATE;
  1295. $$IF(ACTIONMAPPER)
  1296.         msgInputState.fAxisRotateLR = m_UserInput.fAxisRotateLR;
  1297.         msgInputState.fAxisRotateUD = m_UserInput.fAxisRotateUD;
  1298. $$ELSE
  1299.         msgInputState.bRotateUp    = m_UserInput.bRotateUp;
  1300.         msgInputState.bRotateDown  = m_UserInput.bRotateDown;
  1301.         msgInputState.bRotateLeft  = m_UserInput.bRotateLeft;
  1302.         msgInputState.bRotateRight = m_UserInput.bRotateRight;
  1303. $$ENDIF
  1304.  
  1305.         DPN_BUFFER_DESC bufferDesc;
  1306.         bufferDesc.dwBufferSize = sizeof(GAMEMSG_INPUTSTATE);
  1307.         bufferDesc.pBufferData  = (BYTE*) &msgInputState;
  1308.  
  1309.         // Send it to all of the players including the local client
  1310.         // DirectPlay will tell via the message handler 
  1311.         // if there are any severe errors, so ignore any errors 
  1312.         DPNHANDLE hAsync;
  1313.         m_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1314.                        0, NULL, &hAsync, DPNSEND_GUARANTEED );
  1315.     }
  1316.  
  1317.  
  1318.     return S_OK;
  1319. }
  1320.  
  1321.  
  1322.  
  1323.  
  1324. //-----------------------------------------------------------------------------
  1325. // Name: SendWorldStateToAll()
  1326. // Desc: Send the world state to all players on the network
  1327. //-----------------------------------------------------------------------------
  1328. HRESULT CAppForm::SendWorldStateToAll()
  1329. {
  1330.     // Enter world state critical section before accessing world state data 
  1331.     // otherwise one of the DirectPlay threads may change the data
  1332.     // while this thread is accessing it.
  1333.     WORLD_LOCK();
  1334.  
  1335.     GAMEMSG_WORLDSTATE msgWorldState;
  1336.     msgWorldState.nType = GAME_MSGID_WORLDSTATE;
  1337.     msgWorldState.fWorldRotX = m_fWorldRotX;
  1338.     msgWorldState.fWorldRotY = m_fWorldRotY;
  1339.  
  1340.     // Leave the critical section
  1341.     WORLD_UNLOCK();
  1342.  
  1343.     DPN_BUFFER_DESC bufferDesc;
  1344.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_WORLDSTATE);
  1345.     bufferDesc.pBufferData  = (BYTE*) &msgWorldState;
  1346.  
  1347.     // Send the message to all the players except the ourselves
  1348.     // DirectPlay will tell via the message handler 
  1349.     // if there are any severe errors, so ignore any errors 
  1350.     DPNHANDLE hAsync;
  1351.     m_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1352.                    0, NULL, &hAsync, DPNSEND_NOLOOPBACK );
  1353.  
  1354.     return S_OK;
  1355. }
  1356.  
  1357.  
  1358.  
  1359.  
  1360. //-----------------------------------------------------------------------------
  1361. // Name: SendPauseMessageToAll()
  1362. // Desc: Send a pause message to all players on the network
  1363. //-----------------------------------------------------------------------------
  1364. HRESULT CAppForm::SendPauseMessageToAll( BOOL bPause )
  1365. {
  1366.     GAMEMSG_HOSTPAUSE msgPause;
  1367.     msgPause.nType = GAME_MSGID_HOSTPAUSE;
  1368.     msgPause.bHostPause = bPause; 
  1369.  
  1370.     DPN_BUFFER_DESC bufferDesc;
  1371.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_HOSTPAUSE);
  1372.     bufferDesc.pBufferData  = (BYTE*) &msgPause;
  1373.  
  1374.     // Send the message to all the players except the ourselves
  1375.     // DirectPlay will tell via the message handler 
  1376.     // if there are any severe errors, so ignore any errors 
  1377.     DPNHANDLE hAsync;
  1378.     m_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  1379.                    0, NULL, &hAsync, DPNSEND_GUARANTEED | DPNSEND_NOLOOPBACK );
  1380.  
  1381.     return S_OK;
  1382. }
  1383.  
  1384.  
  1385.  
  1386.  
  1387. $$IF(ACTIONMAPPER)
  1388. //-----------------------------------------------------------------------------
  1389. // Name: CombineInputFromAllPlayers()
  1390. // Desc: Combine axis input from all network players
  1391. //-----------------------------------------------------------------------------
  1392. HRESULT CAppForm::CombineInputFromAllPlayers( UserInput* pCombinedUserInput )
  1393. {
  1394.     FLOAT fAxisRotateLRCombined = 0.0f;
  1395.     FLOAT fAxisRotateUDCombined = 0.0f;
  1396.  
  1397.     // Enter player context CS before accessing APP_PLAYER_INFO structs
  1398.     // otherwise one of the DirectPlay threads may delete the struct
  1399.     // while this thread is accessing it.
  1400.     PLAYER_LOCK();                  
  1401.  
  1402.     APP_PLAYER_INFO* pPlayerInfo = m_PlayInfoList.pNext;
  1403.  
  1404.     while( pPlayerInfo != &m_PlayInfoList )
  1405.     {
  1406.         // Use the player whose axis data that is furthest from zero
  1407.         // and if one player is at -1, and another is at +1 then always
  1408.         // choose the positive one.
  1409.         if( fabs(pPlayerInfo->fAxisRotateLR) == fabs(fAxisRotateLRCombined) &&
  1410.                 pPlayerInfo->fAxisRotateLR > 0.0f )
  1411.             fAxisRotateLRCombined = pPlayerInfo->fAxisRotateLR;
  1412.         if( fabs(pPlayerInfo->fAxisRotateLR) > fabs(fAxisRotateLRCombined) )
  1413.             fAxisRotateLRCombined = pPlayerInfo->fAxisRotateLR;
  1414.  
  1415.         if( fabs(pPlayerInfo->fAxisRotateUD) == fabs(fAxisRotateUDCombined) && 
  1416.                 pPlayerInfo->fAxisRotateUD > 0.0f )
  1417.             fAxisRotateUDCombined = pPlayerInfo->fAxisRotateUD;
  1418.         if( fabs(pPlayerInfo->fAxisRotateUD) > fabs(fAxisRotateUDCombined) )
  1419.             fAxisRotateUDCombined = pPlayerInfo->fAxisRotateUD;
  1420.  
  1421.         pPlayerInfo = pPlayerInfo->pNext;
  1422.     }
  1423.  
  1424.     // Leave player context CS
  1425.     PLAYER_UNLOCK();           
  1426.     
  1427.     pCombinedUserInput->fAxisRotateLR = fAxisRotateLRCombined;
  1428.     pCombinedUserInput->fAxisRotateUD = fAxisRotateUDCombined;
  1429.  
  1430.     return S_OK;
  1431. }
  1432.  
  1433.  
  1434.  
  1435.  
  1436. $$ELSE // start !ACTIONMAPPER
  1437. //-----------------------------------------------------------------------------
  1438. // Name: CombineInputFromAllPlayers()
  1439. // Desc: Combine axis input from all network players
  1440. //-----------------------------------------------------------------------------
  1441. HRESULT CAppForm::CombineInputFromAllPlayers( UserInput* pCombinedUserInput )
  1442. {
  1443.     pCombinedUserInput->bRotateUp    = FALSE;
  1444.     pCombinedUserInput->bRotateDown  = FALSE;
  1445.     pCombinedUserInput->bRotateLeft  = FALSE;
  1446.     pCombinedUserInput->bRotateRight = FALSE;
  1447.  
  1448.     // Enter player context CS before accessing APP_PLAYER_INFO structs
  1449.     // otherwise one of the DirectPlay threads may delete the struct
  1450.     // while this thread is accessing it.
  1451.     PLAYER_LOCK();                  
  1452.  
  1453.     APP_PLAYER_INFO* pPlayerInfo = m_PlayInfoList.pNext;
  1454.  
  1455.     while( pPlayerInfo != &m_PlayInfoList )
  1456.     {
  1457.         // Use the player whose axis data that is furthest from zero
  1458.         // and if one player is at -1, and another is at +1 then always
  1459.         // choose the positive one.
  1460.         if( pPlayerInfo->bRotateUp )
  1461.             pCombinedUserInput->bRotateUp = TRUE;
  1462.         if( pPlayerInfo->bRotateDown )
  1463.             pCombinedUserInput->bRotateDown = TRUE;
  1464.         if( pPlayerInfo->bRotateLeft )
  1465.             pCombinedUserInput->bRotateLeft = TRUE;
  1466.         if( pPlayerInfo->bRotateRight )
  1467.             pCombinedUserInput->bRotateRight = TRUE;
  1468.  
  1469.         pPlayerInfo = pPlayerInfo->pNext;
  1470.     }
  1471.  
  1472.     // Leave player context CS
  1473.     PLAYER_UNLOCK();           
  1474.     
  1475.     return S_OK;
  1476. }
  1477.  
  1478.  
  1479.  
  1480.  
  1481. $$ENDIF // end ACTIONMAPPER
  1482. $$ENDIF // end DPLAY
  1483. $$IF(DPLAYVOICE)
  1484. //-----------------------------------------------------------------------------
  1485. // Name: UpdateTalkingVariables()
  1486. // Desc: Update m_bNetworkPlayersTalking and m_bLocalPlayerTalking
  1487. //-----------------------------------------------------------------------------
  1488. VOID CAppForm::UpdateTalkingVariables()
  1489. {
  1490.     // Enter player critical section before accessing player's state data 
  1491.     // otherwise the DirectPlay network threads may change the data
  1492.     // while this thread is accessing it.
  1493.     PLAYER_LOCK();      
  1494.  
  1495.     APP_PLAYER_INFO* pPlayerInfo = m_PlayInfoList.pNext;
  1496.  
  1497.     m_bNetworkPlayersTalking = FALSE;
  1498.     while( pPlayerInfo != &m_PlayInfoList )
  1499.     {
  1500.         // If any player besides the local player is talking, then set
  1501.         // m_bNetworkPlayersTalking to TRUE
  1502.         if( pPlayerInfo != m_pLocalPlayerInfo && pPlayerInfo->bTalking )
  1503.             m_bNetworkPlayersTalking = TRUE;
  1504.  
  1505.         pPlayerInfo = pPlayerInfo->pNext;
  1506.     }
  1507.  
  1508.     // Update m_bLocalPlayerTalking
  1509.     m_bLocalPlayerTalking = m_pLocalPlayerInfo->bTalking;
  1510.  
  1511.     PLAYER_UNLOCK();                
  1512. }
  1513.  
  1514.  
  1515.  
  1516.  
  1517. $$ENDIF // DPLAYVOICE
  1518. //-----------------------------------------------------------------------------
  1519. // Name: CAppForm::Render()
  1520. // Desc: Called once per frame, the call is the entry point for 3d
  1521. //       rendering. This function sets up render states, clears the
  1522. //       viewport, and renders the scene.
  1523. //-----------------------------------------------------------------------------
  1524. HRESULT CAppForm::Render()
  1525. {
  1526.     // Clear the viewport
  1527.     m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
  1528.                          0x000000ff, 1.0f, 0L );
  1529.  
  1530.     // Begin the scene
  1531.     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  1532.     {
  1533.         // TODO: render world
  1534.         
  1535. $$IF(SHOW_TRIANGLE)
  1536.         // Render the vertex buffer contents
  1537.         m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(CUSTOMVERTEX) );
  1538.         m_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );
  1539.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );
  1540.  
  1541. $$ENDIF // SHOW_TRIANGLE
  1542. $$IF(SHOW_TEAPOT)
  1543.         // Render the teapot mesh
  1544.         m_pD3DXMesh->DrawSubset(0);
  1545.  
  1546. $$ENDIF // SHOW_TEAPOT
  1547.         // Render stats and help text  
  1548.         RenderText();
  1549.  
  1550.         // End the scene.
  1551.         m_pd3dDevice->EndScene();
  1552.     }
  1553.  
  1554.     return S_OK;
  1555. }
  1556.  
  1557.  
  1558.  
  1559.  
  1560. //-----------------------------------------------------------------------------
  1561. // Name: RenderText()
  1562. // Desc: Renders stats and help text to the scene.
  1563. //-----------------------------------------------------------------------------
  1564. HRESULT CAppForm::RenderText()
  1565. {
  1566.     D3DCOLOR fontColor        = D3DCOLOR_ARGB(255,255,255,0);
  1567.     D3DCOLOR fontWarningColor = D3DCOLOR_ARGB(255,0,255,255);
  1568.     TCHAR szMsg[MAX_PATH] = TEXT("");
  1569. $$IF(!D3DFONT)
  1570.     RECT rct;
  1571.     ZeroMemory( &rct, sizeof(rct) );       
  1572.  
  1573.     m_pD3DXFont->Begin();
  1574.     rct.left   = 2;
  1575.     rct.right  = m_d3dsdBackBuffer.Width - 20;
  1576. $$ELSE
  1577. $$ENDIF
  1578.  
  1579.     // Output display stats
  1580. $$IF(!D3DFONT)
  1581.     INT nNextLine = 40; 
  1582. $$ELSE
  1583.     FLOAT fNextLine = 40.0f; 
  1584. $$ENDIF
  1585.  
  1586. $$// ******************************************************
  1587.     lstrcpy( szMsg, m_strDeviceStats );
  1588. $$// ------------------------------------------------------
  1589. $$IF(D3DFONT)
  1590.     fNextLine -= 20.0f;
  1591.     m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1592. $$ELSE
  1593.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1594.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1595. $$ENDIF
  1596. $$// ------------------------------------------------------
  1597.  
  1598. $$// ******************************************************
  1599.     lstrcpy( szMsg, m_strFrameStats );
  1600. $$// ------------------------------------------------------
  1601. $$IF(D3DFONT)
  1602.     fNextLine -= 20.0f;
  1603.     m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1604. $$ELSE
  1605.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1606.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1607. $$ENDIF
  1608. $$// ------------------------------------------------------
  1609.  
  1610.     // Output statistics & help
  1611. $$IF(!D3DFONT)
  1612.     nNextLine = m_d3dsdBackBuffer.Height; 
  1613. $$ELSE
  1614.     fNextLine = (FLOAT) m_d3dsdBackBuffer.Height; 
  1615. $$ENDIF
  1616.  
  1617. $$IF(DPLAY)
  1618. $$IF(ACTIONMAPPER)
  1619. $$// ******************************************************
  1620.     sprintf( szMsg, TEXT("Network Combined L/R Axis: %0.2f U/D Axis: %0.2f "), 
  1621.               m_CombinedNetworkInput.fAxisRotateLR, m_CombinedNetworkInput.fAxisRotateUD );
  1622. $$// ------------------------------------------------------
  1623. $$IF(D3DFONT)
  1624.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1625. $$ELSE
  1626.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1627.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1628. $$ENDIF
  1629. $$// ------------------------------------------------------
  1630.  
  1631. $$ELSE // start !ACTIONMAPPER
  1632. $$// ******************************************************
  1633.     wsprintf( szMsg, TEXT("Network Combined Keys: U=%d D=%d L=%d R=%d"), 
  1634.               m_CombinedNetworkInput.bRotateUp, m_CombinedNetworkInput.bRotateDown, m_CombinedNetworkInput.bRotateLeft, m_CombinedNetworkInput.bRotateRight );
  1635. $$// ------------------------------------------------------
  1636. $$IF(D3DFONT)
  1637.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1638. $$ELSE
  1639.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1640.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1641. $$ENDIF
  1642. $$// ------------------------------------------------------
  1643.  
  1644. $$ENDIF // ACTIONMAPPER
  1645. $$ENDIF // DPLAY
  1646. $$IF(ACTIONMAPPER)
  1647. $$// ******************************************************
  1648. $$IF(DPLAY)
  1649.     sprintf( szMsg, TEXT("Local Left/Right Axis: %0.2f Up/Down Axis: %0.2f "), 
  1650.               m_UserInput.fAxisRotateLR, m_UserInput.fAxisRotateUD );
  1651. $$ELSE
  1652.     sprintf( szMsg, TEXT("Left/Right Axis: %0.2f Up/Down Axis: %0.2f "), 
  1653.               m_UserInput.fAxisRotateLR, m_UserInput.fAxisRotateUD );
  1654. $$ENDIF
  1655. $$// ------------------------------------------------------
  1656. $$IF(D3DFONT)
  1657.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1658. $$ELSE
  1659.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1660.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1661. $$ENDIF
  1662. $$// ------------------------------------------------------
  1663.  
  1664. $$ELSE // start !ACTIONMAPPER
  1665. $$IF(DPLAY)
  1666. $$// ******************************************************
  1667.     wsprintf( szMsg, TEXT("Local Arrow keys: U=%d D=%d L=%d R=%d"), 
  1668.               m_UserInput.bRotateUp, m_UserInput.bRotateDown, m_UserInput.bRotateLeft, m_UserInput.bRotateRight );
  1669. $$ELSE
  1670.     wsprintf( szMsg, TEXT("Arrow keys: Up=%d Down=%d Left=%d Right=%d"), 
  1671.               m_UserInput.bRotateUp, m_UserInput.bRotateDown, m_UserInput.bRotateLeft, m_UserInput.bRotateRight );
  1672. $$ENDIF
  1673. $$// ------------------------------------------------------
  1674. $$IF(D3DFONT)
  1675.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1676. $$ELSE
  1677.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1678.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1679. $$ENDIF
  1680. $$// ------------------------------------------------------
  1681.  
  1682. $$ENDIF // ACTIONMAPPER
  1683. $$IF(DPLAY)
  1684. $$// ******************************************************
  1685.     sprintf( szMsg, TEXT("%d player(s) in session %s"), 
  1686.                         m_lNumberOfActivePlayers, 
  1687.                         m_pNetConnectWizard->IsHostPlayer() ? TEXT("(Hosting)") : TEXT("") );
  1688. $$// ------------------------------------------------------
  1689. $$IF(D3DFONT)
  1690.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1691. $$ELSE
  1692.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1693.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1694. $$ENDIF
  1695. $$// ------------------------------------------------------
  1696.  
  1697. $$ENDIF // DPLAY
  1698. $$IF(DPLAYVOICE)
  1699. $$// ******************************************************
  1700.     sprintf( szMsg, TEXT("Local Player: %s  Network Players: %s"), 
  1701.                         m_bLocalPlayerTalking ? TEXT("Talking") : TEXT("Silent"), 
  1702.                         m_bNetworkPlayersTalking ? TEXT("Talking") : TEXT("Silent") );
  1703. $$// ------------------------------------------------------
  1704. $$IF(D3DFONT)
  1705.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1706. $$ELSE
  1707.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1708.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1709. $$ENDIF
  1710. $$// ------------------------------------------------------
  1711.  
  1712. $$ENDIF // DPLAYVOICE
  1713. $$IF(!SHOW_TRIANGLE)
  1714. $$IF(!SHOW_TEAPOT)
  1715. $$// ******************************************************
  1716.     sprintf( szMsg, TEXT("World State: %0.3f, %0.3f"), 
  1717.                     m_fWorldRotX, m_fWorldRotY );
  1718. $$// ------------------------------------------------------
  1719. $$IF(D3DFONT)
  1720.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1721. $$ELSE
  1722.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1723.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1724. $$ENDIF
  1725. $$// ------------------------------------------------------
  1726.  
  1727. $$ENDIF // !SHOW_TEAPOT
  1728. $$ENDIF // !SHOW_TRIANGLE
  1729. $$IF(SHOW_TRIANGLE || SHOW_TEAPOT)
  1730. $$IF(ACTIONMAPPER)
  1731. $$// ******************************************************
  1732.     lstrcpy( szMsg, TEXT("Use arrow keys or joystick to rotate object") );
  1733. $$// ------------------------------------------------------
  1734. $$IF(D3DFONT)
  1735.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1736. $$ELSE
  1737.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1738.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1739. $$ENDIF
  1740. $$// ------------------------------------------------------
  1741.  
  1742. $$ELSE // start !ACTIONMAPPER
  1743. $$// ******************************************************
  1744.     lstrcpy( szMsg, TEXT("Use arrow keys to rotate object") );
  1745. $$// ------------------------------------------------------
  1746. $$IF(D3DFONT)
  1747.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1748. $$ELSE
  1749.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1750.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1751. $$ENDIF
  1752. $$// ------------------------------------------------------
  1753.  
  1754. $$ENDIF // ACTIONMAPPER
  1755. $$ELSE // start !(SHOW_TRIANGLE || SHOW_TEAPOT)
  1756. $$IF(ACTIONMAPPER)
  1757. $$// ******************************************************
  1758.     lstrcpy( szMsg, TEXT("Use arrow keys or joystick to update input") );
  1759. $$// ------------------------------------------------------
  1760. $$IF(D3DFONT)
  1761.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1762. $$ELSE
  1763.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1764.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1765. $$ENDIF
  1766. $$// ------------------------------------------------------
  1767.  
  1768. $$ELSE // start !ACTIONMAPPER
  1769.     lstrcpy( szMsg, TEXT("Use arrow keys to update input") );
  1770. $$// ------------------------------------------------------
  1771. $$IF(D3DFONT)
  1772.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1773. $$ELSE
  1774.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1775.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1776. $$ENDIF
  1777. $$// ------------------------------------------------------
  1778.  
  1779. $$ENDIF // ACTIONMAPPER
  1780. $$ENDIF // SHOW_TRIANGLE || SHOW_TEAPOT
  1781. $$IF(DMUSIC || DSOUND)
  1782. $$// ******************************************************
  1783.     lstrcpy( szMsg, TEXT("Hold 'F5' down to play and repeat a sound") );
  1784. $$// ------------------------------------------------------
  1785. $$IF(D3DFONT)
  1786.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1787. $$ELSE
  1788.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1789.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1790. $$ENDIF
  1791. $$// ------------------------------------------------------
  1792.  
  1793. $$ENDIF // DMUSIC || DSOUND
  1794. $$IF(DPLAYVOICE)
  1795. $$// ******************************************************
  1796.     lstrcpy( szMsg, TEXT("Press 'F4' to configure voice") );
  1797. $$// ------------------------------------------------------
  1798. $$IF(D3DFONT)
  1799.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1800. $$ELSE
  1801.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1802.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1803. $$ENDIF
  1804. $$// ------------------------------------------------------
  1805.  
  1806. $$ENDIF // DPLAYVOICE
  1807. $$IF(ACTIONMAPPER)
  1808. $$// ******************************************************
  1809.     lstrcpy( szMsg, TEXT("Press 'F3' to configure input") );
  1810. $$// ------------------------------------------------------
  1811. $$IF(D3DFONT)
  1812.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1813. $$ELSE
  1814.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1815.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1816. $$ENDIF
  1817. $$// ------------------------------------------------------
  1818.  
  1819. $$ENDIF // ACTIONMAPPER
  1820. $$// ******************************************************
  1821.     lstrcpy( szMsg, TEXT("Press 'F2' to configure display") );
  1822. $$// ------------------------------------------------------
  1823. $$IF(D3DFONT)
  1824.     fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontColor, szMsg );
  1825. $$ELSE
  1826.     nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1827.     m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontColor );
  1828. $$ENDIF
  1829. $$// ------------------------------------------------------
  1830.  
  1831. $$IF(DPLAY)
  1832.     if( m_bHostPausing )
  1833.     {
  1834. $$// ******************************************************
  1835.         lstrcpy( szMsg, TEXT("Paused waiting for host...") );
  1836. $$// ------------------------------------------------------
  1837. $$IF(D3DFONT)
  1838.         fNextLine -= 20.0f; m_pFont->DrawText( 2, fNextLine, fontWarningColor, szMsg );
  1839. $$ELSE
  1840.         nNextLine -= 20; rct.top = nNextLine; rct.bottom = rct.top + 20;    
  1841.         m_pD3DXFont->DrawText( szMsg, -1, &rct, 0, fontWarningColor );
  1842. $$ENDIF
  1843. $$// ------------------------------------------------------   
  1844.     }
  1845.  
  1846. $$ENDIF // DPLAY
  1847. $$IF(!D3DFONT)
  1848.     m_pD3DXFont->End();
  1849.  
  1850. $$ENDIF
  1851.     return S_OK;
  1852. }
  1853.  
  1854.  
  1855.  
  1856.  
  1857. $$IF(DPLAY || ACTIONMAPPER)
  1858. //-----------------------------------------------------------------------------
  1859. // Name: Pause()
  1860. // Desc: Called in to toggle the pause state of the app.
  1861. //-----------------------------------------------------------------------------
  1862. VOID CAppForm::Pause( BOOL bPause )
  1863. {
  1864. $$IF(DPLAY)
  1865.     // Tell the other apps to pause or unpause if this is the host
  1866.     if( m_pNetConnectWizard && m_pNetConnectWizard->IsHostPlayer() )
  1867.         SendPauseMessageToAll( bPause );
  1868.  
  1869. $$ENDIF
  1870. $$IF(ACTIONMAPPER)
  1871.     // Get access to the list of semantically-mapped input devices
  1872.     // to zero the state of all InputDeviceState structs.  This is needed
  1873.     // because when using DISCL_FOREGROUND, the action mapper will not 
  1874.     // record actions when the focus switches, for example if a dialog appears.
  1875.     // This causes a problem when a button held down when loosing focus, and let
  1876.     // go when the focus is lost.  The app will not record that the button 
  1877.     // has been let go, so the state will be incorrect when focus returns.  
  1878.     // To fix this either use DISCL_BACKGROUND or zero the state when 
  1879.     // loosing focus.
  1880.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  1881.     DWORD dwNumDevices;
  1882.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  1883.  
  1884.     for( DWORD i=0; i<dwNumDevices; i++ )
  1885.     {
  1886.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  1887.         ZeroMemory( pInputDeviceState, sizeof(InputDeviceState) );
  1888.     }
  1889.  
  1890. $$ENDIF
  1891.     CD3DApplication::Pause( bPause );
  1892. }
  1893.  
  1894.  
  1895.  
  1896.  
  1897. $$ENDIF // end DPLAY || ACTIONMAPPER
  1898. //-----------------------------------------------------------------------------
  1899. // Name: DoDataExchange()
  1900. // Desc: DDX/DDV support
  1901. //-----------------------------------------------------------------------------
  1902. void CAppForm::DoDataExchange(CDataExchange* pDX)
  1903. {
  1904.     CFormView::DoDataExchange(pDX);
  1905.     //{{AFX_DATA_MAP(CAppForm)
  1906.     //}}AFX_DATA_MAP
  1907. }
  1908.  
  1909.  
  1910.  
  1911.  
  1912. //-----------------------------------------------------------------------------
  1913. // Name: WindowProc()
  1914. // Desc: 
  1915. //-----------------------------------------------------------------------------
  1916. LRESULT CAppForm::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
  1917. {
  1918. $$IF(ACTIONMAPPER | DPLAYVOICE)
  1919.     switch( message )
  1920.     {
  1921.         case WM_COMMAND:
  1922.         {
  1923.             switch( LOWORD(wParam) )
  1924.             {
  1925. $$IF(ACTIONMAPPER)
  1926.                 case IDM_CONFIGINPUT:
  1927.                     m_UserInput.bDoConfigureInput = TRUE;
  1928.                     break;
  1929.  
  1930.                 case IDC_CHANGEDEVICE:
  1931.                 case IDM_CHANGEDEVICE:
  1932.                     m_UserInput.bDoConfigureDisplay = TRUE;
  1933.                     return 0; // Don't hand off to parent
  1934. $$ENDIF 
  1935. $$IF(DPLAYVOICE)
  1936.  
  1937.                 case IDM_CONFIGVOICE:
  1938.                     m_UserInput.bDoConfigureVoice = TRUE;
  1939.                     break;
  1940. $$ENDIF
  1941.             }
  1942.             break;
  1943.         }
  1944.     }
  1945.     
  1946. $$ENDIF // end (ACTIONMAPPER | DPLAYVOICE)
  1947.     return CFormView ::WindowProc(message, wParam, lParam);
  1948. }
  1949.  
  1950.  
  1951.  
  1952.  
  1953. //-----------------------------------------------------------------------------
  1954. // Name: OnChangeDevice()
  1955. // Desc: Needed to enable dlg menu item 
  1956. //-----------------------------------------------------------------------------
  1957. void CAppFrameWnd::OnChangeDevice() 
  1958. {
  1959. $$IF(ACTIONMAPPER)
  1960.     g_AppFormView->m_UserInput.bDoConfigureDisplay = TRUE;
  1961. $$ELSE
  1962.     g_AppFormView->OnChangeDevice();
  1963. $$ENDIF
  1964. }
  1965.  
  1966.  
  1967.  
  1968.  
  1969. $$IF(ACTIONMAPPER)
  1970. //-----------------------------------------------------------------------------
  1971. // Name: OnConfigInput()
  1972. // Desc: 
  1973. //-----------------------------------------------------------------------------
  1974. void CAppFrameWnd::OnConfigInput() 
  1975. {
  1976.     g_AppFormView->m_UserInput.bDoConfigureInput = TRUE;
  1977. }
  1978.  
  1979.  
  1980.  
  1981.  
  1982. $$ENDIF
  1983. $$IF(DPLAYVOICE)
  1984. //-----------------------------------------------------------------------------
  1985. // Name: OnConfigVoice()
  1986. // Desc: 
  1987. //-----------------------------------------------------------------------------
  1988. void CAppFrameWnd::OnConfigVoice() 
  1989. {
  1990.     g_AppFormView->m_UserInput.bDoConfigureVoice = TRUE;
  1991. }
  1992.  
  1993.  
  1994.  
  1995.  
  1996. $$ENDIF
  1997. $$IF(DPLAYVOICE)
  1998. //-----------------------------------------------------------------------------
  1999. // Name: UserConfigVoice()
  2000. // Desc: Allow user to configure the voice settings
  2001. //-----------------------------------------------------------------------------
  2002. HRESULT CAppForm::UserConfigVoice()
  2003. {
  2004.     HRESULT hr;
  2005.     BOOL bWasFullscreen = FALSE;
  2006.    
  2007.     // Can't display dialogs in fullscreen mode
  2008.     if( m_bWindowed == FALSE )
  2009.     {
  2010.         bWasFullscreen = TRUE;
  2011.  
  2012.         if( FAILED( ToggleFullscreen() ) )
  2013.         {
  2014.             DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  2015.             return E_FAIL;
  2016.         }
  2017.     }
  2018.  
  2019.     // Configure the voice settings, store the settings in 
  2020.     // m_guidDVSessionCT & m_dvClientConfig
  2021.     // TODO: replace with a fancier graphics layer like D3D.
  2022.     if( m_pNetVoice )
  2023.     {
  2024.         hr = m_pNetVoice->DoVoiceSetupDialog( g_hInst, m_hWndTopLevelParent, &m_guidDVSessionCT, &m_dvClientConfig );
  2025.  
  2026.         // If the settings dialog was not canceled, then change the settings
  2027.         if( hr != DVERR_USERCANCEL )
  2028.             m_pNetVoice->ChangeVoiceClientSettings( &m_dvClientConfig );
  2029.     }
  2030.  
  2031.     // Return to fullscreen mode after dialogs
  2032.     if( bWasFullscreen )
  2033.     {
  2034.         if( FAILED( ToggleFullscreen() ) )
  2035.         {
  2036.             DisplayErrorMsg( D3DAPPERR_RESIZEFAILED, MSGERR_APPMUSTEXIT );
  2037.             return E_FAIL;
  2038.         }
  2039.     }
  2040.     
  2041.     return S_OK;
  2042. }
  2043.  
  2044.  
  2045.  
  2046.  
  2047. $$ENDIF
  2048. //-----------------------------------------------------------------------------
  2049. // Name: CAppForm::InvalidateDeviceObjects()
  2050. // Desc: Called when the device-dependent objects are about to be lost.
  2051. //-----------------------------------------------------------------------------
  2052. HRESULT CAppForm::InvalidateDeviceObjects()
  2053. {
  2054.     // TODO: Cleanup any objects created in RestoreDeviceObjects()
  2055. $$IF(D3DFONT)
  2056.     m_pFont->InvalidateDeviceObjects();
  2057. $$ELSE    
  2058.     SAFE_RELEASE( m_pD3DXFont );
  2059. $$ENDIF
  2060. $$IF(ACTIONMAPPER)
  2061.     SAFE_RELEASE( m_pDIConfigSurface );
  2062. $$ENDIF
  2063.  
  2064.     return S_OK;
  2065. }
  2066.  
  2067.  
  2068.  
  2069.  
  2070. //-----------------------------------------------------------------------------
  2071. // Name: CAppForm::DeleteDeviceObjects()
  2072. // Desc: Called when the app is exiting, or the device is being changed,
  2073. //       this function deletes any device dependent objects.
  2074. //-----------------------------------------------------------------------------
  2075. HRESULT CAppForm::DeleteDeviceObjects()
  2076. {
  2077.     // TODO: Cleanup any objects created in InitDeviceObjects()
  2078. $$IF(D3DFONT)
  2079.     m_pFont->DeleteDeviceObjects();
  2080. $$ENDIF
  2081. $$IF(SHOW_TRIANGLE)
  2082.     SAFE_RELEASE( m_pVB );
  2083. $$ENDIF
  2084. $$IF(SHOW_TEAPOT)
  2085.     SAFE_RELEASE( m_pD3DXMesh );
  2086. $$ENDIF
  2087.  
  2088.     return S_OK;
  2089. }
  2090.  
  2091.  
  2092.  
  2093.  
  2094. //-----------------------------------------------------------------------------
  2095. // Name: CAppForm::FinalCleanup()
  2096. // Desc: Called before the app exits, this function gives the app the chance
  2097. //       to cleanup after itself.
  2098. //-----------------------------------------------------------------------------
  2099. HRESULT CAppForm::FinalCleanup()
  2100. {
  2101.     // TODO: Perform any final cleanup needed
  2102. $$IF(D3DFONT)
  2103.     // Cleanup D3D font
  2104.     SAFE_DELETE( m_pFont );
  2105.  
  2106. $$ENDIF
  2107. $$IF(DINPUT)
  2108.     // Cleanup DirectInput
  2109.     CleanupDirectInput();
  2110.  
  2111. $$ENDIF
  2112. $$IF(DMUSIC || DSOUND)
  2113.     // Cleanup DirectX audio objects
  2114.     SAFE_DELETE( m_pBounceSound );
  2115. $$IF(DMUSIC)
  2116.     SAFE_DELETE( m_pMusicManager );
  2117. $$ELSE // start !DMUSIC
  2118.     SAFE_DELETE( m_pSoundManager );
  2119. $$ENDIF // end DMUSIC
  2120.  
  2121. $$ENDIF // end (DMUSIC || DSOUND)
  2122. $$IF(DPLAY)
  2123.     // Cleanup DirectPlay
  2124.     CleanupDirectPlay();
  2125.  
  2126.     // Cleanup COM
  2127.     CoUninitialize();
  2128.  
  2129. $$ENDIF
  2130.     // Write the settings to the registry
  2131.     WriteSettings();
  2132.  
  2133.     return S_OK;
  2134. }
  2135.  
  2136.  
  2137.  
  2138.  
  2139. $$IF(DPLAY)
  2140. //-----------------------------------------------------------------------------
  2141. // Name: StaticDirectPlayMessageHandler
  2142. // Desc: Static callback helper to call into CAppForm class
  2143. //-----------------------------------------------------------------------------
  2144. HRESULT WINAPI CAppForm::StaticDirectPlayMessageHandler( PVOID pvUserContext, 
  2145.                                                                   DWORD dwMessageId, 
  2146.                                                                   PVOID pMsgBuffer )
  2147. {
  2148.     if( g_AppFormView )
  2149.         return g_AppFormView->DirectPlayMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  2150.     return S_OK;
  2151. }
  2152.  
  2153.  
  2154.  
  2155.  
  2156. //-----------------------------------------------------------------------------
  2157. // Name: DirectPlayMessageHandler
  2158. // Desc: Handler for DirectPlay messages.  This function is called by
  2159. //       the DirectPlay message handler pool of threads, so be careful of thread
  2160. //       synchronization problems with shared memory
  2161. //-----------------------------------------------------------------------------
  2162. HRESULT CAppForm::DirectPlayMessageHandler( PVOID pvUserContext, 
  2163.                                                      DWORD dwMessageId, 
  2164.                                                      PVOID pMsgBuffer )
  2165. {
  2166.     // Try not to stay in this message handler for too long, otherwise
  2167.     // there will be a backlog of data.  The best solution is to 
  2168.     // queue data as it comes in, and then handle it on other threads.
  2169.     
  2170.     // This function is called by the DirectPlay message handler pool of 
  2171.     // threads, so be careful of thread synchronization problems with shared memory
  2172.  
  2173.     switch( dwMessageId )
  2174.     {
  2175.         case DPN_MSGID_CREATE_PLAYER:
  2176.         {
  2177.             HRESULT hr;
  2178.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  2179.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer;
  2180.  
  2181.             // Get the peer info and extract its name
  2182.             DWORD dwSize = 0;
  2183.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  2184.             hr = m_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, 
  2185.                                      pdpPlayerInfo, &dwSize, 0 );
  2186.             if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  2187.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  2188.             pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  2189.             ZeroMemory( pdpPlayerInfo, dwSize );
  2190.             pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  2191.             hr = m_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, 
  2192.                                      pdpPlayerInfo, &dwSize, 0 );
  2193.             if( FAILED(hr) )
  2194.                 return DXTRACE_ERR( TEXT("GetPeerInfo"), hr );
  2195.  
  2196.             // Create a new and fill in a APP_PLAYER_INFO
  2197.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  2198.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) );
  2199.             pPlayerInfo->lRefCount   = 1;
  2200.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  2201.  
  2202.             // This stores a extra TCHAR copy of the player name for 
  2203.             // easier access.  This will be redundant copy since DPlay 
  2204.             // also keeps a copy of the player name in GetPeerInfo()
  2205.             DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  2206.                                                pdpPlayerInfo->pwszName, MAX_PATH );
  2207.  
  2208.             if( pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL )
  2209.             {
  2210.                 m_dpnidLocalPlayer = pCreatePlayerMsg->dpnidPlayer;
  2211.                 m_pLocalPlayerInfo = pPlayerInfo;
  2212.  
  2213.                 // Increase the ref if this is the local player, so the struct 
  2214.                 // won't be deleted when DirectPlay shuts down.  The
  2215.                 // main window thread will release the struct when it is done
  2216.                 pPlayerInfo->lRefCount++;
  2217.             }
  2218.             else
  2219.             {
  2220.                 if( m_pNetConnectWizard->IsHostPlayer() )
  2221.                 {
  2222.                     // If the local player is the host and 
  2223.                     // this DPN_MSGID_CREATE_PLAYER is not for the local player
  2224.                     // then set the m_fWorldSyncTimer to fire immediately so
  2225.                     // the new player will get the state of the world
  2226.                     m_fWorldSyncTimer = 0.0f;
  2227.                 }
  2228.             }
  2229.  
  2230.             // Add the APP_PLAYER_INFO to the circular linked list, m_PlayInfoList
  2231.             pPlayerInfo->pNext = m_PlayInfoList.pNext;
  2232.             pPlayerInfo->pPrev = &m_PlayInfoList;
  2233.             m_PlayInfoList.pNext->pPrev = pPlayerInfo;    
  2234.             m_PlayInfoList.pNext = pPlayerInfo;    
  2235.  
  2236.             SAFE_DELETE_ARRAY( pdpPlayerInfo );
  2237.  
  2238.             // Tell DirectPlay to store this pPlayerInfo 
  2239.             // pointer in the pvPlayerContext.
  2240.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  2241.  
  2242.             // Update the number of active players, and if the app needs to 
  2243.             // tell the UI immediately about this, then post a message to 
  2244.             // the window thread.  This keeps the DirectPlay message handler 
  2245.             // from blocking
  2246.             InterlockedIncrement( &m_lNumberOfActivePlayers );
  2247.             break;
  2248.         }
  2249.  
  2250.         case DPN_MSGID_RECEIVE:
  2251.         {
  2252.             PDPNMSG_RECEIVE pReceiveMsg;
  2253.             pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;
  2254.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pReceiveMsg->pvPlayerContext;
  2255.  
  2256.             GAMEMSG_GENERIC* pMsg = (GAMEMSG_GENERIC*) pReceiveMsg->pReceiveData;
  2257.             switch( pMsg->nType )
  2258.             {
  2259.                 case GAME_MSGID_INPUTSTATE:
  2260.                 {
  2261.                     // Update the APP_PLAYER_INFO struct associated with this
  2262.                     // network player with the data send in the GAMEMSG_INPUTSTATE.
  2263.                     GAMEMSG_INPUTSTATE* pInputStateMsg = (GAMEMSG_INPUTSTATE*) pMsg;
  2264.  
  2265.                     // Enter player critical section before accessing player's state data 
  2266.                     // otherwise the main thread or other DirectPlay threads may access the data
  2267.                     // while this thread is changing it.
  2268.                     PLAYER_LOCK();                  
  2269.  
  2270. $$IF(ACTIONMAPPER)
  2271.                     pPlayerInfo->fAxisRotateLR = pInputStateMsg->fAxisRotateLR;
  2272.                     pPlayerInfo->fAxisRotateUD = pInputStateMsg->fAxisRotateUD;
  2273. $$ELSE
  2274.                     pPlayerInfo->bRotateUp    = pInputStateMsg->bRotateUp;
  2275.                     pPlayerInfo->bRotateDown  = pInputStateMsg->bRotateDown;
  2276.                     pPlayerInfo->bRotateLeft  = pInputStateMsg->bRotateLeft;
  2277.                     pPlayerInfo->bRotateRight = pInputStateMsg->bRotateRight;
  2278. $$ENDIF
  2279.  
  2280.                     PLAYER_UNLOCK();                // leave player context CS
  2281.                     break;
  2282.                 }
  2283.  
  2284.                 case GAME_MSGID_WORLDSTATE:
  2285.                 {
  2286.                     // Enter world state critical section before accessing world state data 
  2287.                     // otherwise the main thread or other DirectPlay threads may access the data
  2288.                     // while this thread is changing it.
  2289.                     WORLD_LOCK();
  2290.  
  2291.                     // Update the world state with the data from GAMEMSG_WORLDSTATE
  2292.                     GAMEMSG_WORLDSTATE* pMsgWorldState = (GAMEMSG_WORLDSTATE*) pMsg;
  2293.                     m_fWorldRotX = pMsgWorldState->fWorldRotX;
  2294.                     m_fWorldRotY = pMsgWorldState->fWorldRotY;
  2295.  
  2296.                     // Leave the critical section
  2297.                     WORLD_UNLOCK();
  2298.                     break;
  2299.                 }
  2300.  
  2301.                 case GAME_MSGID_HOSTPAUSE:
  2302.                 {
  2303.                     GAMEMSG_HOSTPAUSE* pMsgPause = (GAMEMSG_HOSTPAUSE*) pMsg;
  2304.  
  2305.                     // Update the pause state with the data from GAMEMSG_HOSTPAUSE
  2306.                     m_bHostPausing = pMsgPause->bHostPause;
  2307.                     break;
  2308.                 }
  2309.             }
  2310.             break;
  2311.         }
  2312.  
  2313.         case DPN_MSGID_DESTROY_PLAYER:
  2314.         {
  2315.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  2316.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  2317.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  2318.  
  2319.             PLAYER_LOCK();                  // enter player context CS
  2320.  
  2321.             // Remove pPlayerInfo from the circular linked list
  2322.             pPlayerInfo->pNext->pPrev = pPlayerInfo->pPrev;
  2323.             pPlayerInfo->pPrev->pNext = pPlayerInfo->pNext;
  2324.  
  2325.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  2326.             PLAYER_UNLOCK();                // leave player context CS
  2327.  
  2328.             // Update the number of active players, and if the app needs to 
  2329.             // tell the UI immediately about this, then post a message to 
  2330.             // the window thread.  This keeps the DirectPlay message handler 
  2331.             // from blocking
  2332.             InterlockedDecrement( &m_lNumberOfActivePlayers );
  2333.             break;
  2334.         }
  2335.  
  2336.         case DPN_MSGID_TERMINATE_SESSION:
  2337.         {
  2338.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  2339.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  2340.  
  2341.             m_hrNet = DPNERR_CONNECTIONLOST;
  2342.  
  2343.             // Close the window, which shuts down the app
  2344.             PostMessage( WM_CLOSE, 0, 0 );
  2345.             break;
  2346.         }
  2347.     }
  2348.  
  2349.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  2350.     // so it can be informed of messages such as DPN_MSGID_ENUM_HOSTS_RESPONSE.
  2351.     if( m_pNetConnectWizard )
  2352.         return m_pNetConnectWizard->MessageHandler( pvUserContext, dwMessageId, 
  2353.                                                     pMsgBuffer );
  2354.     
  2355.     return S_OK;
  2356. }
  2357.  
  2358.  
  2359.  
  2360.  
  2361. //-----------------------------------------------------------------------------
  2362. // Name: StaticDirectPlayLobbyMessageHandler
  2363. // Desc: Static callback helper to call into CAppForm class
  2364. //-----------------------------------------------------------------------------
  2365. HRESULT WINAPI CAppForm::StaticDirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  2366.                                                                   DWORD dwMessageId, 
  2367.                                                                   PVOID pMsgBuffer )
  2368. {
  2369.     if( g_AppFormView )
  2370.         return g_AppFormView->DirectPlayLobbyMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  2371.     return S_OK;
  2372. }
  2373.  
  2374.  
  2375.  
  2376.  
  2377. //-----------------------------------------------------------------------------
  2378. // Name: DirectPlayLobbyMessageHandler
  2379. // Desc: Handler for DirectPlay lobby messages.  This function is called by
  2380. //       the DirectPlay lobby message handler pool of threads, so be careful of 
  2381. //       thread synchronization problems with shared memory
  2382. //-----------------------------------------------------------------------------
  2383. HRESULT CAppForm::DirectPlayLobbyMessageHandler( PVOID pvUserContext, 
  2384.                                                           DWORD dwMessageId, 
  2385.                                                           PVOID pMsgBuffer )
  2386. {
  2387.     switch( dwMessageId )
  2388.     {
  2389.         case DPL_MSGID_CONNECT:
  2390.         {
  2391.             PDPL_MESSAGE_CONNECT pConnectMsg;
  2392.             pConnectMsg = (PDPL_MESSAGE_CONNECT)pMsgBuffer;
  2393.  
  2394.             // The CNetConnectWizard will handle this message for us,
  2395.             // so there is nothing we need to do here for this simple
  2396.             // sample.
  2397.             break;
  2398.         }
  2399.  
  2400.         case DPL_MSGID_DISCONNECT:
  2401.         {
  2402.             PDPL_MESSAGE_DISCONNECT pDisconnectMsg;
  2403.             pDisconnectMsg = (PDPL_MESSAGE_DISCONNECT)pMsgBuffer;
  2404.  
  2405.             // We should free any data associated with the lobby 
  2406.             // client here, but there is none.
  2407.             break;
  2408.         }
  2409.  
  2410.         case DPL_MSGID_RECEIVE:
  2411.         {
  2412.             PDPL_MESSAGE_RECEIVE pReceiveMsg;
  2413.             pReceiveMsg = (PDPL_MESSAGE_RECEIVE)pMsgBuffer;
  2414.  
  2415.             // The lobby client sent us data.  This sample doesn't
  2416.             // expected data from the client, but it is useful 
  2417.             // for more complex apps.
  2418.             break;
  2419.         }
  2420.  
  2421.         case DPL_MSGID_CONNECTION_SETTINGS:
  2422.         {
  2423.             PDPL_MESSAGE_CONNECTION_SETTINGS pConnectionStatusMsg;
  2424.             pConnectionStatusMsg = (PDPL_MESSAGE_CONNECTION_SETTINGS)pMsgBuffer;
  2425.  
  2426.             // The lobby client has changed the connection settings.  
  2427.             // This simple sample doesn't handle this, but more complex apps may
  2428.             // want to.
  2429.             break;
  2430.         }
  2431.     }
  2432.  
  2433.     // Make sure the DirectPlay MessageHandler calls the CNetConnectWizard handler, 
  2434.     // so the wizard can be informed of lobby messages such as DPL_MSGID_CONNECT
  2435.     if( m_pNetConnectWizard )
  2436.         return m_pNetConnectWizard->LobbyMessageHandler( pvUserContext, dwMessageId, 
  2437.                                                          pMsgBuffer );
  2438.     
  2439.     return S_OK;
  2440. }
  2441.  
  2442.  
  2443.  
  2444.  
  2445. $$ENDIF
  2446. $$IF(DPLAYVOICE)
  2447. //-----------------------------------------------------------------------------
  2448. // Name: StaticDirectPlayVoiceServerMessageHandler
  2449. // Desc: Static callback helper to call into CAppForm class
  2450. //-----------------------------------------------------------------------------
  2451. HRESULT WINAPI CAppForm::StaticDirectPlayVoiceServerMessageHandler( PVOID pvUserContext, 
  2452.                                                                   DWORD dwMessageId, 
  2453.                                                                   PVOID pMsgBuffer )
  2454. {
  2455.     if( g_AppFormView )
  2456.         return g_AppFormView->DirectPlayVoiceServerMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  2457.     return S_OK;
  2458. }
  2459.  
  2460.  
  2461.  
  2462.  
  2463. //-----------------------------------------------------------------------------
  2464. // Name: DirectPlayVoiceServerMessageHandler()
  2465. // Desc: The callback for DirectPlayVoice server messages.  
  2466. //-----------------------------------------------------------------------------
  2467. HRESULT CAppForm::DirectPlayVoiceServerMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  2468.                                                                 LPVOID lpMessage )
  2469. {
  2470.     // This simple sample doesn't respond to any server messages
  2471.     return S_OK;
  2472. }
  2473.  
  2474.  
  2475.  
  2476.  
  2477. //-----------------------------------------------------------------------------
  2478. // Name: StaticDirectPlayVoiceClientMessageHandler
  2479. // Desc: Static callback helper to call into CAppForm class
  2480. //-----------------------------------------------------------------------------
  2481. HRESULT WINAPI CAppForm::StaticDirectPlayVoiceClientMessageHandler( PVOID pvUserContext, 
  2482.                                                                   DWORD dwMessageId, 
  2483.                                                                   PVOID pMsgBuffer )
  2484. {
  2485.     if( g_AppFormView )
  2486.         return g_AppFormView->DirectPlayVoiceClientMessageHandler( pvUserContext, dwMessageId, pMsgBuffer );
  2487.     return S_OK;
  2488. }
  2489.  
  2490.  
  2491.  
  2492.  
  2493. //-----------------------------------------------------------------------------
  2494. // Name: DirectPlayVoiceClientMessageHandler()
  2495. // Desc: The callback for DirectPlayVoice client messages.  
  2496. //       This handles client messages and updates the UI the whenever a client 
  2497. //       starts or stops talking.  
  2498. //-----------------------------------------------------------------------------
  2499. HRESULT CAppForm::DirectPlayVoiceClientMessageHandler( LPVOID lpvUserContext, DWORD dwMessageType,
  2500.                                                                 LPVOID lpMessage )
  2501. {
  2502.     // Try not to stay in this message handler for too long, otherwise
  2503.     // there will be a backlog of data.  The best solution is to 
  2504.     // queue data as it comes in, and then handle it on other threads.
  2505.     
  2506.     // This function is called by the DirectPlay message handler pool of 
  2507.     // threads, so be care of thread synchronization problems with shared memory
  2508.  
  2509.     HRESULT hr;
  2510.     HWND hDlg = (HWND) lpvUserContext;
  2511.  
  2512.     switch( dwMessageType )
  2513.     {
  2514.         case DVMSGID_CREATEVOICEPLAYER:
  2515.         {
  2516.             DVMSG_CREATEVOICEPLAYER* pCreateVoicePlayerMsg = (DVMSG_CREATEVOICEPLAYER*) lpMessage;
  2517.             APP_PLAYER_INFO* pPlayerInfo = NULL;
  2518.  
  2519.             // Enter player critical section before accessing player's state data 
  2520.             // otherwise the main thread or other DirectPlay threads may access the data
  2521.             // while this thread is changing it.
  2522.             PLAYER_LOCK(); 
  2523.  
  2524.             // Get the player context associated with this DPNID
  2525.             hr = m_pDP->GetPlayerContext( pCreateVoicePlayerMsg->dvidPlayer, 
  2526.                                           (LPVOID* const) &pPlayerInfo, 0);
  2527.  
  2528.             if( FAILED(hr) || pPlayerInfo == NULL )
  2529.             {
  2530.                 // The player who sent this may have gone away before this 
  2531.                 // message was handled, so just ignore it
  2532.                 PLAYER_UNLOCK();
  2533.                 break;
  2534.             }
  2535.  
  2536.             // Addref player struct, so it can used freely by the voice layer
  2537.             PLAYER_ADDREF( pPlayerInfo ); 
  2538.  
  2539.             pPlayerInfo->bHalfDuplex = ((pCreateVoicePlayerMsg->dwFlags & DVPLAYERCAPS_HALFDUPLEX) != 0);
  2540.  
  2541.             PLAYER_UNLOCK(); // leave player context CS
  2542.  
  2543.             // Set voice context value
  2544.             pCreateVoicePlayerMsg->pvPlayerContext = pPlayerInfo;
  2545.  
  2546.             // We're leaving the extra reference, so the voice layer will 
  2547.             // own that reference
  2548.             break;
  2549.         }
  2550.  
  2551.         case DVMSGID_DELETEVOICEPLAYER:
  2552.         {
  2553.             DVMSG_DELETEVOICEPLAYER* pMsg = (DVMSG_DELETEVOICEPLAYER*) lpMessage;
  2554.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  2555.  
  2556.             // Release our extra reference on the player info that we have for the voice
  2557.             // context value.  
  2558.             PLAYER_LOCK();
  2559.             PLAYER_RELEASE( pPlayerInfo );  
  2560.             PLAYER_UNLOCK();
  2561.             break;
  2562.         }            
  2563.  
  2564.         case DVMSGID_RECORDSTART:             
  2565.         { 
  2566.             DVMSG_RECORDSTART* pMsg = (DVMSG_RECORDSTART*) lpMessage;
  2567.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext;
  2568.  
  2569.             PLAYER_LOCK();
  2570.             if( pPlayerInfo )
  2571.                 pPlayerInfo->bTalking = TRUE;   
  2572.             PLAYER_UNLOCK();
  2573.             break;
  2574.         }
  2575.  
  2576.         case DVMSGID_RECORDSTOP:             
  2577.         {
  2578.             DVMSG_RECORDSTOP* pMsg = (DVMSG_RECORDSTOP*) lpMessage;
  2579.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvLocalPlayerContext;
  2580.  
  2581.             PLAYER_LOCK();
  2582.             if( pPlayerInfo )
  2583.                 pPlayerInfo->bTalking = FALSE;  
  2584.             PLAYER_UNLOCK();
  2585.             break;
  2586.         }
  2587.  
  2588.         case DVMSGID_PLAYERVOICESTART:
  2589.         {
  2590.             DVMSG_PLAYERVOICESTART* pMsg = (DVMSG_PLAYERVOICESTART*) lpMessage;
  2591.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  2592.  
  2593.             PLAYER_LOCK();
  2594.             if( pPlayerInfo )
  2595.                 pPlayerInfo->bTalking = TRUE;   
  2596.             PLAYER_UNLOCK();
  2597.             break;
  2598.         }
  2599.  
  2600.         case DVMSGID_PLAYERVOICESTOP:
  2601.         {
  2602.             DVMSG_PLAYERVOICESTOP* pMsg = (DVMSG_PLAYERVOICESTOP*) lpMessage;
  2603.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pMsg->pvPlayerContext;
  2604.  
  2605.             PLAYER_LOCK();
  2606.             if( pPlayerInfo )
  2607.                 pPlayerInfo->bTalking = FALSE;  
  2608.             PLAYER_UNLOCK();
  2609.             break;
  2610.         }
  2611.     }
  2612.  
  2613.     return S_OK;
  2614. }
  2615.  
  2616.  
  2617.  
  2618.  
  2619. $$ENDIF
  2620. $$IF(DPLAY)
  2621. //-----------------------------------------------------------------------------
  2622. // Name: CleanupDirectPlay()
  2623. // Desc: Cleanup DirectPlay 
  2624. //-----------------------------------------------------------------------------
  2625. VOID CAppForm::CleanupDirectPlay()
  2626. {
  2627. $$IF(DPLAYVOICE)
  2628.     // Disconnect from the DirectPlayVoice session, 
  2629.     // and destroy it if we are the host player.
  2630.     SAFE_DELETE( m_pNetVoice ); 
  2631.  
  2632. $$ENDIF
  2633.     // Cleanup DirectPlay and helper classes
  2634.     if( m_pNetConnectWizard )
  2635.         m_pNetConnectWizard->Shutdown();
  2636.  
  2637.     if( m_pDP )
  2638.     {
  2639.         m_pDP->Close(0);
  2640.         SAFE_RELEASE( m_pDP );
  2641.     }
  2642.  
  2643.     if( m_pLobbiedApp )
  2644.     {
  2645.         m_pLobbiedApp->Close( 0 );
  2646.         SAFE_RELEASE( m_pLobbiedApp );
  2647.     }    
  2648.  
  2649.     PLAYER_LOCK();                  // enter player context CS
  2650.     PLAYER_RELEASE( m_pLocalPlayerInfo ); // Release player and cleanup if needed
  2651.     PLAYER_UNLOCK();                // leave player context CS
  2652.  
  2653.     // Don't delete the wizard until we know that 
  2654.     // DirectPlay is out of its message handlers.
  2655.     // This will be true after Close() has been called. 
  2656.     SAFE_DELETE( m_pNetConnectWizard );
  2657.     DeleteCriticalSection( &g_csPlayerContext );
  2658.     DeleteCriticalSection( &g_csWorldStateContext );
  2659.  
  2660.     if( m_hrNet == DPNERR_CONNECTIONLOST )
  2661.     {
  2662.         MessageBox( TEXT("The DirectPlay session was lost. ")
  2663.                     TEXT("The sample will now quit."),
  2664.                     TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  2665.     }
  2666. }
  2667.  
  2668.  
  2669.  
  2670. $$ENDIF
  2671. $$IF(DINPUT)
  2672. //-----------------------------------------------------------------------------
  2673. // Name: CleanupDirectInput()
  2674. // Desc: Cleanup DirectInput 
  2675. //-----------------------------------------------------------------------------
  2676. VOID CAppForm::CleanupDirectInput()
  2677. {
  2678. $$IF(KEYBOARD)
  2679.     // Cleanup DirectX input objects
  2680.     SAFE_RELEASE( m_pKeyboard );
  2681.     SAFE_RELEASE( m_pDI );
  2682.  
  2683. $$ENDIF
  2684. $$IF(ACTIONMAPPER)
  2685.     if( NULL == m_pInputDeviceManager )
  2686.         return;
  2687.  
  2688.     // Get access to the list of semantically-mapped input devices
  2689.     // to delete all InputDeviceState structs
  2690.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  2691.     DWORD dwNumDevices;
  2692.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  2693.  
  2694.     for( DWORD i=0; i<dwNumDevices; i++ )
  2695.     {
  2696.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  2697.         SAFE_DELETE( pInputDeviceState );
  2698.         pDeviceInfos[i].pParam = NULL;
  2699.     }
  2700.  
  2701.     // Cleanup DirectX input objects
  2702.     SAFE_DELETE( m_pInputDeviceManager );
  2703.  
  2704. $$ENDIF
  2705. }
  2706.  
  2707.  
  2708.  
  2709.  
  2710. $$ENDIF
  2711. //-----------------------------------------------------------------------------
  2712. // Name: InitInstance()
  2713. // Desc: This is the main entry point for the application. The MFC window stuff
  2714. //       is initialized here. See also the main initialization routine for the
  2715. //       CAppForm class, which is called indirectly from here.
  2716. //-----------------------------------------------------------------------------
  2717. BOOL CApp::InitInstance()
  2718. {
  2719.     // Asscociate the MFC app with the frame window and doc/view classes
  2720.     AddDocTemplate( new CSingleDocTemplate( IDR_MAINFRAME,
  2721.                                             RUNTIME_CLASS(CAppDoc),
  2722.                                             RUNTIME_CLASS(CAppFrameWnd),
  2723.                                             RUNTIME_CLASS(CAppForm) ) );
  2724.  
  2725.     // Dispatch commands specified on the command line (req'd by MFC). This
  2726.     // also initializes the the CAppDoc, CAppFrameWnd, and CAppForm classes.
  2727.     CCommandLineInfo cmdInfo;
  2728.     ParseCommandLine( cmdInfo );
  2729.     if( !ProcessShellCommand( cmdInfo ) )
  2730.         return FALSE;
  2731.  
  2732.     if( !g_AppFormView->IsReady() )
  2733.         return FALSE;
  2734.  
  2735.     g_AppFormView->GetParentFrame()->RecalcLayout();
  2736.     g_AppFormView->ResizeParentToFit( FALSE ); 
  2737.     
  2738.     m_pMainWnd->SetWindowText( g_strAppTitle );
  2739.     m_pMainWnd->UpdateWindow();
  2740.  
  2741.     return TRUE;
  2742. }
  2743.  
  2744.  
  2745.  
  2746.  
  2747. //-----------------------------------------------------------------------------
  2748. // Name: LoadFrame()
  2749. // Desc: Uses idle time to render the 3D scene.
  2750. //-----------------------------------------------------------------------------
  2751. BOOL CAppFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext) 
  2752. {
  2753.     BOOL bResult = CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle, pParentWnd, pContext);
  2754.  
  2755.     LoadAccelTable( MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
  2756.  
  2757.     return bResult;
  2758. }
  2759.  
  2760.  
  2761.  
  2762.  
  2763. //-----------------------------------------------------------------------------
  2764. // Name: OnIdle()
  2765. // Desc: Uses idle time to render the 3D scene.
  2766. //-----------------------------------------------------------------------------
  2767. BOOL CApp::OnIdle( LONG )
  2768. {
  2769.     // Do not render if the app is minimized
  2770.     if( m_pMainWnd->IsIconic() )
  2771.         return FALSE;
  2772.  
  2773.     TCHAR strStatsPrev[200];
  2774.  
  2775.     lstrcpy(strStatsPrev, g_AppFormView->PstrFrameStats());
  2776.  
  2777.     // Update and render a frame
  2778.     if( g_AppFormView->IsReady() )
  2779.     {
  2780.         g_AppFormView->CheckForLostFullscreen();
  2781.         g_AppFormView->RenderScene();
  2782.     }
  2783.  
  2784.     // Keep requesting more idle time
  2785.     return TRUE;
  2786. }
  2787.  
  2788.  
  2789.  
  2790.  
  2791. //-----------------------------------------------------------------------------
  2792. // Name: PreCreateWindow()
  2793. // Desc: Change the window style (so it cannot maximize or be sized) before
  2794. //       the main frame window is created.
  2795. //-----------------------------------------------------------------------------
  2796. BOOL CAppFrameWnd::PreCreateWindow( CREATESTRUCT& cs )
  2797. {
  2798.     cs.style = WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX;
  2799.  
  2800.     return CFrameWnd::PreCreateWindow( cs );
  2801. }
  2802.  
  2803.  
  2804.  
  2805.  
  2806. //-----------------------------------------------------------------------------
  2807. // Name: ~CAppForm()
  2808. // Desc: Destructor for the dialog resource form. Shuts down the app
  2809. //-----------------------------------------------------------------------------
  2810. CAppForm::~CAppForm()
  2811. {
  2812.     Cleanup3DEnvironment();
  2813. }
  2814.  
  2815.  
  2816.  
  2817.  
  2818. //-----------------------------------------------------------------------------
  2819. // Name: OnToggleFullScreen()
  2820. // Desc: Called when user toggles the fullscreen mode
  2821. //-----------------------------------------------------------------------------
  2822. void CAppForm::OnToggleFullScreen()
  2823. {
  2824.     ToggleFullscreen();
  2825. }
  2826.  
  2827.  
  2828.  
  2829.  
  2830. //-----------------------------------------------------------------------------
  2831. // Name: OnChangeDevice()
  2832. // Desc: Use hit the "Change Device.." button. Display the dialog for the user
  2833. //       to select a new device/mode, and call Change3DEnvironment to
  2834. //       use the new device/mode.
  2835. //-----------------------------------------------------------------------------
  2836. VOID CAppForm::OnChangeDevice()
  2837. {
  2838.     Pause(TRUE);
  2839.  
  2840.     UserSelectNewDevice();
  2841.  
  2842.     // Update UI
  2843.     UpdateUIForDeviceCapabilites();
  2844.  
  2845.     Pause(FALSE);
  2846. }
  2847.  
  2848.  
  2849.  
  2850.  
  2851. //-----------------------------------------------------------------------------
  2852. // Name: AdjustWindowForChange()
  2853. // Desc: Adjusts the window properties for windowed or fullscreen mode
  2854. //-----------------------------------------------------------------------------
  2855. HRESULT CAppForm::AdjustWindowForChange()
  2856. {
  2857.     if( m_bWindowed )
  2858.     {
  2859.         ::ShowWindow( m_hwndRenderFullScreen, SW_HIDE );
  2860.         CD3DApplication::m_hWnd = m_hwndRenderWindow;
  2861. $$IF(ACTIONMAPPER)
  2862.  
  2863.         // Tell the action mapper that the focus wnd has changed
  2864.         m_pInputDeviceManager->SetFocus( m_hWndTopLevelParent );
  2865. $$ENDIF
  2866. $$IF(KEYBOARD)
  2867.  
  2868.         // Tell the action mapper that the focus wnd has changed
  2869.         m_pKeyboard->SetCooperativeLevel( m_hWndTopLevelParent, 
  2870.                                                 DISCL_NONEXCLUSIVE | 
  2871.                                                 DISCL_FOREGROUND | 
  2872.                                                 DISCL_NOWINKEY );
  2873. $$ENDIF
  2874.     }
  2875.     else
  2876.     {
  2877.         if( ::IsIconic( m_hwndRenderFullScreen ) )
  2878.             ::ShowWindow( m_hwndRenderFullScreen, SW_RESTORE );
  2879.         ::ShowWindow( m_hwndRenderFullScreen, SW_SHOW );
  2880.         CD3DApplication::m_hWnd = m_hwndRenderFullScreen;
  2881. $$IF(ACTIONMAPPER)
  2882.  
  2883.         // Tell the action mapper that the focus wnd has changed
  2884.         m_pInputDeviceManager->SetFocus( m_hwndRenderFullScreen );
  2885. $$ENDIF
  2886. $$IF(KEYBOARD)
  2887.  
  2888.         // Tell the action mapper that the focus wnd has changed
  2889.         m_pKeyboard->SetCooperativeLevel( m_hwndRenderFullScreen, 
  2890.                                                 DISCL_NONEXCLUSIVE | 
  2891.                                                 DISCL_FOREGROUND | 
  2892.                                                 DISCL_NOWINKEY );
  2893. $$ENDIF
  2894.     }
  2895.  
  2896.     return S_OK;
  2897. }
  2898.  
  2899.  
  2900.  
  2901.  
  2902. //-----------------------------------------------------------------------------
  2903. // Name: FullScreenWndProc()
  2904. // Desc: The WndProc funtion used when the app is in fullscreen mode. This is
  2905. //       needed simply to trap the ESC key.
  2906. //-----------------------------------------------------------------------------
  2907. LRESULT CALLBACK FullScreenWndProc( HWND hWnd, UINT msg, WPARAM wParam,
  2908.                                     LPARAM lParam )
  2909. {
  2910.     if( msg == WM_CLOSE )
  2911.     {
  2912.         // User wants to exit, so go back to windowed mode and exit for real
  2913.         g_AppFormView->OnToggleFullScreen();
  2914.         g_App.GetMainWnd()->PostMessage( WM_CLOSE, 0, 0 );
  2915.     }
  2916.     else if( msg == WM_SETCURSOR )
  2917.     {
  2918.         SetCursor( NULL );
  2919.     }
  2920.     else if( msg == WM_KEYUP && wParam == VK_ESCAPE )
  2921.     {
  2922.         // User wants to leave fullscreen mode
  2923.         g_AppFormView->OnToggleFullScreen();
  2924.     }
  2925.  
  2926.     return DefWindowProc( hWnd, msg, wParam, lParam );
  2927. }
  2928.  
  2929.  
  2930.  
  2931.  
  2932. //-----------------------------------------------------------------------------
  2933. // Name: CheckForLostFullscreen()
  2934. // Desc: If fullscreen and device was lost (probably due to alt-tab), 
  2935. //       automatically switch to windowed mode
  2936. //-----------------------------------------------------------------------------
  2937. HRESULT CAppForm::CheckForLostFullscreen()
  2938. {
  2939.     HRESULT hr;
  2940.  
  2941.     if( m_bWindowed )
  2942.         return S_OK;
  2943.  
  2944.     if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
  2945.         ForceWindowed();
  2946.  
  2947.     return S_OK;
  2948. }
  2949.  
  2950.  
  2951.  
  2952.  
  2953. //-----------------------------------------------------------------------------
  2954. // Name: UpdateUIForDeviceCapabilites()
  2955. // Desc: Whenever we get a new device, call this function to enable/disable the
  2956. //       appropiate UI controls to match the device's capabilities.
  2957. //-----------------------------------------------------------------------------
  2958. VOID CAppForm::UpdateUIForDeviceCapabilites()
  2959. {
  2960.     // TODO: Check the capabilities of the device and update the UI as needed
  2961.     DWORD dwCaps = m_d3dCaps.RasterCaps;
  2962. }
  2963.  
  2964.  
  2965.  
  2966.  
  2967. //-----------------------------------------------------------------------------
  2968. // Name: OnInitialUpdate()
  2969. // Desc: When the AppForm object is created, this function is called to
  2970. //       initialize it. Here we getting access ptrs to some of the controls,
  2971. //       and setting the initial state of some of them as well.
  2972. //-----------------------------------------------------------------------------
  2973. VOID CAppForm::OnInitialUpdate()
  2974. {
  2975.     // Update the UI
  2976.     CFormView::OnInitialUpdate();
  2977.  
  2978.     // Get the top level parent hwnd
  2979.     m_hWndTopLevelParent = GetTopLevelParent()->GetSafeHwnd();
  2980.  
  2981.     // Save static reference to the render window
  2982.     m_hwndRenderWindow = GetDlgItem(IDC_RENDERVIEW)->GetSafeHwnd();
  2983.  
  2984.     // Register a class for a fullscreen window
  2985.     WNDCLASS wndClass = { CS_HREDRAW | CS_VREDRAW, FullScreenWndProc, 0, 0, NULL,
  2986.                           NULL, NULL, (HBRUSH)GetStockObject(WHITE_BRUSH), NULL,
  2987.                           _T("Fullscreen Window") };
  2988.     RegisterClass( &wndClass );
  2989.  
  2990.     // We create the fullscreen window (not visible) at startup, so it can
  2991.     // be the focus window.  The focus window can only be set at CreateDevice
  2992.     // time, not in a Reset, so ToggleFullscreen wouldn't work unless we have
  2993.     // already set up the fullscreen focus window.
  2994.     m_hwndRenderFullScreen = CreateWindow( _T("Fullscreen Window"), NULL,
  2995.                                            WS_POPUP, CW_USEDEFAULT,
  2996.                                            CW_USEDEFAULT, 100, 100,
  2997.                                            m_hWndTopLevelParent, 0L, NULL, 0L );
  2998.  
  2999.     // Note that for the MFC samples, the device window and focus window
  3000.     // are not the same.
  3001.     CD3DApplication::m_hWnd = m_hwndRenderWindow;
  3002.     CD3DApplication::m_hWndFocus = m_hwndRenderFullScreen;
  3003.     CD3DApplication::Create( AfxGetInstanceHandle() );
  3004.  
  3005.     // TODO: Update the UI as needed
  3006. }
  3007.  
  3008.  
  3009.  
  3010.  
  3011.