home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / Source / Chapter 10 / Engine / Engine.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2005-03-29  |  15.6 KB  |  478 lines

  1. //-----------------------------------------------------------------------------
  2. // Engine.h implementation.
  3. // Refer to the Engine.h interface for more details.
  4. //
  5. // Programming a Multiplayer First Person Shooter in DirectX
  6. // Copyright (c) 2004 Vaughan Young
  7. //-----------------------------------------------------------------------------
  8. #include "Engine.h"
  9.  
  10. //-----------------------------------------------------------------------------
  11. // Globals
  12. //-----------------------------------------------------------------------------
  13. Engine *g_engine = NULL;
  14.  
  15. //-----------------------------------------------------------------------------
  16. // Handles Windows messages.
  17. //-----------------------------------------------------------------------------
  18. LRESULT CALLBACK WindowProc( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam )
  19. {
  20.     switch( msg )
  21.     {
  22.         case WM_ACTIVATEAPP:
  23.             g_engine->SetDeactiveFlag( !wparam );
  24.             return 0;
  25.  
  26.         case WM_DESTROY:
  27.             PostQuitMessage( 0 );
  28.             return 0;
  29.  
  30.         default:
  31.             return DefWindowProc( wnd, msg, wparam, lparam );
  32.     }
  33. }
  34.  
  35. //-----------------------------------------------------------------------------
  36. // The engine class constructor.
  37. //-----------------------------------------------------------------------------
  38. Engine::Engine( EngineSetup *setup )
  39. {
  40.     // Indicate that the engine is not yet loaded.
  41.     m_loaded = false;
  42.  
  43.     // If no setup structure was passed in, then create a default one.
  44.     // Otehrwise, make a copy of the passed in structure.
  45.     m_setup = new EngineSetup;
  46.     if( setup != NULL )
  47.         memcpy( m_setup, setup, sizeof( EngineSetup ) );
  48.  
  49.     // Store a pointer to the engine in a global variable for easy access.
  50.     g_engine = this;
  51.  
  52.     // Prepare and register the window class.
  53.     WNDCLASSEX wcex;
  54.     wcex.cbSize        = sizeof( WNDCLASSEX );
  55.     wcex.style         = CS_CLASSDC;
  56.     wcex.lpfnWndProc   = WindowProc;
  57.     wcex.cbClsExtra    = 0;
  58.     wcex.cbWndExtra    = 0;
  59.     wcex.hInstance     = m_setup->instance;
  60.     wcex.hIcon         = LoadIcon( NULL, IDI_APPLICATION );
  61.     wcex.hCursor       = LoadCursor( NULL, IDC_ARROW );
  62.     wcex.hbrBackground = NULL;
  63.     wcex.lpszMenuName  = NULL;
  64.     wcex.lpszClassName = "WindowClass";
  65.     wcex.hIconSm       = LoadIcon( NULL, IDI_APPLICATION );
  66.     RegisterClassEx( &wcex );
  67.  
  68.     // Initialise the COM using multithreaded concurrency.
  69.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  70.  
  71.     // Create the Direct3D interface.
  72.     IDirect3D9 *d3d = Direct3DCreate9( D3D_SDK_VERSION );
  73.  
  74.     // Enumerate Direct3D device configurations on the default adapter.
  75.     g_deviceEnumeration = new DeviceEnumeration;
  76.     if( g_deviceEnumeration->Enumerate( d3d ) != IDOK )
  77.     {
  78.         SAFE_RELEASE( d3d );
  79.         return;
  80.     }
  81.  
  82.     // Create the window and retrieve a handle to it.
  83.     m_window = CreateWindow( "WindowClass", m_setup->name, g_deviceEnumeration->IsWindowed() ? WS_OVERLAPPED : WS_POPUP, 0, 0, 800, 600, NULL, NULL, m_setup->instance, NULL );
  84.  
  85.     // Prepare the device presentation parameters.
  86.     D3DPRESENT_PARAMETERS d3dpp;
  87.     ZeroMemory( &d3dpp, sizeof( D3DPRESENT_PARAMETERS ) );
  88.     d3dpp.BackBufferWidth = g_deviceEnumeration->GetSelectedDisplayMode()->Width;
  89.     d3dpp.BackBufferHeight = g_deviceEnumeration->GetSelectedDisplayMode()->Height;
  90.     d3dpp.BackBufferFormat = g_deviceEnumeration->GetSelectedDisplayMode()->Format;
  91.     d3dpp.BackBufferCount = m_setup->totalBackBuffers;
  92.     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
  93.     d3dpp.hDeviceWindow = m_window;
  94.     d3dpp.Windowed = g_deviceEnumeration->IsWindowed();
  95.     d3dpp.EnableAutoDepthStencil = true;
  96.     d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
  97.     d3dpp.FullScreen_RefreshRateInHz = g_deviceEnumeration->GetSelectedDisplayMode()->RefreshRate;
  98.     if( g_deviceEnumeration->IsVSynced() == true )
  99.         d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
  100.     else
  101.         d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  102.  
  103.     // Destroy the device enumeration object.
  104.     SAFE_DELETE( g_deviceEnumeration );
  105.  
  106.     // Create the Direct3D device.
  107.     if( FAILED( d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_window, D3DCREATE_MIXED_VERTEXPROCESSING, &d3dpp, &m_device ) ) )
  108.         return;
  109.  
  110.     // Release the Direct3D interface as it is no longer needed.
  111.     SAFE_RELEASE( d3d );
  112.  
  113.     // Switch lighting off by default.
  114.     m_device->SetRenderState( D3DRS_LIGHTING, false );
  115.  
  116.     // Set the texture filters to use anisotropic texture filtering.
  117.     m_device->SetSamplerState ( 0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC );
  118.     m_device->SetSamplerState ( 0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC );
  119.     m_device->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR );
  120.  
  121.     // Set the projection matrix.
  122.     D3DXMATRIX projMatrix;
  123.     D3DXMatrixPerspectiveFovLH( &projMatrix, D3DX_PI / 4, (float)d3dpp.BackBufferWidth / (float)d3dpp.BackBufferHeight, 0.1f / m_setup->scale, 1000.0f / m_setup->scale );
  124.     m_device->SetTransform( D3DTS_PROJECTION, &projMatrix );
  125.  
  126.     // Store the display mode details.
  127.     m_displayMode.Width = d3dpp.BackBufferWidth;
  128.     m_displayMode.Height = d3dpp.BackBufferHeight;
  129.     m_displayMode.RefreshRate = d3dpp.FullScreen_RefreshRateInHz;
  130.     m_displayMode.Format = d3dpp.BackBufferFormat;
  131.  
  132.     // The swap chain always starts on the first back buffer.
  133.     m_currentBackBuffer = 0;
  134.  
  135.     // Create the sprite interface.
  136.     D3DXCreateSprite( m_device, &m_sprite );
  137.  
  138.     // Create the linked lists of states.
  139.     m_states = new LinkedList< State >;
  140.     m_currentState = NULL;
  141.  
  142.     // Create the resource managers.
  143.     m_scriptManager = new ResourceManager< Script >;
  144.     m_materialManager = new ResourceManager< Material >( m_setup->CreateMaterialResource );
  145.     m_meshManager = new ResourceManager< Mesh >;
  146.  
  147.     // Create the input object.
  148.     m_input = new Input( m_window );
  149.  
  150.     // Create the network object.
  151.     m_network = new Network( m_setup->guid, m_setup->HandleNetworkMessage );
  152.  
  153.     // Create the sound system.
  154.     m_soundSystem = new SoundSystem( m_setup->scale );
  155.  
  156.     // Create the scene manager.
  157.     m_sceneManager = new SceneManager( m_setup->scale, m_setup->spawnerPath );
  158.  
  159.     // Seed the random number generator with the current time.
  160.     srand( timeGetTime() );
  161.  
  162.     // Allow the application to perform any state setup now.
  163.     if( m_setup->StateSetup != NULL )
  164.         m_setup->StateSetup();
  165.  
  166.     // The engine is fully loaded and ready to go.
  167.     m_loaded = true;
  168. }
  169.  
  170. //-----------------------------------------------------------------------------
  171. // The engine class destructor.
  172. //-----------------------------------------------------------------------------
  173. Engine::~Engine()
  174. {
  175.     // Ensure the engine is loaded.
  176.     if( m_loaded == true )
  177.     {
  178.         // Destroy the states linked lists.
  179.         if( m_currentState != NULL )
  180.             m_currentState->Close();
  181.         SAFE_DELETE( m_states );
  182.  
  183.         // Destroy everything.
  184.         SAFE_DELETE( m_sceneManager );
  185.         SAFE_DELETE( m_soundSystem );
  186.         SAFE_DELETE( m_network );
  187.         SAFE_DELETE( m_input );
  188.         SAFE_DELETE( m_meshManager );
  189.         SAFE_DELETE( m_materialManager );
  190.         SAFE_DELETE( m_scriptManager );
  191.  
  192.         // Release the sprite interface.
  193.         SAFE_RELEASE( m_sprite );
  194.  
  195.         // Release the device.
  196.         SAFE_RELEASE( m_device );
  197.     }
  198.  
  199.     // Uninitialise the COM.
  200.     CoUninitialize();
  201.  
  202.     // Unregister the window class.
  203.     UnregisterClass( "WindowClass", m_setup->instance );
  204.  
  205.     // Destroy the engine setup structure.
  206.     SAFE_DELETE( m_setup );
  207. }
  208.  
  209. //-----------------------------------------------------------------------------
  210. // Enters the engine into the main processing loop.
  211. //-----------------------------------------------------------------------------
  212. void Engine::Run()
  213. {
  214.     // Ensure the engine is loaded.
  215.     if( m_loaded == true )
  216.     {
  217.         // Show the window.
  218.         ShowWindow( m_window, SW_NORMAL );
  219.  
  220.         // Used to retrieve details about the viewer from the application.
  221.         ViewerSetup viewer;
  222.  
  223.         // Enter the message loop.
  224.         MSG msg;
  225.         ZeroMemory( &msg, sizeof( MSG ) );
  226.         while( msg.message != WM_QUIT )
  227.         {
  228.             if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
  229.             {
  230.                 TranslateMessage( &msg );
  231.                 DispatchMessage( &msg );
  232.             }
  233.             else if( !m_deactive )
  234.             {
  235.                 // Calculate the elapsed time.
  236.                 unsigned long currentTime = timeGetTime();
  237.                 static unsigned long lastTime = currentTime;
  238.                 float elapsed = ( currentTime - lastTime ) / 1000.0f;
  239.                 lastTime = currentTime;
  240.  
  241.                 // Update the network object, processing any pending messages.
  242.                 m_network->Update();
  243.  
  244.                 // Update the input object, reading the keyboard and mouse.
  245.                 m_input->Update();
  246.  
  247.                 // Check if the user wants to make a forced exit.
  248.                 if( m_input->GetKeyPress( DIK_F1 ) )
  249.                     PostQuitMessage( 0 );
  250.  
  251.                 // Request the viewer from the current state, if there is one.
  252.                 if( m_currentState != NULL )
  253.                     m_currentState->RequestViewer( &viewer );
  254.  
  255.                 // Ensure the viewer is valid.
  256.                 if( viewer.viewer != NULL )
  257.                 {
  258.                     // Update the scene.
  259.                     m_sceneManager->Update( elapsed, viewer.viewer->GetViewMatrix() );
  260.  
  261.                     // Set the view transformation.
  262.                     m_device->SetTransform( D3DTS_VIEW, viewer.viewer->GetViewMatrix() );
  263.  
  264.                     // Update the 3D sound listener.
  265.                     m_soundSystem->UpdateListener( viewer.viewer->GetForwardVector(), viewer.viewer->GetTranslation(), viewer.viewer->GetVelocity() );
  266.                 }
  267.  
  268.                 // Update the current state (if there is one), taking state
  269.                 // changes into account.
  270.                 m_stateChanged = false;
  271.                 if( m_currentState != NULL )
  272.                     m_currentState->Update( elapsed );
  273.                 if( m_stateChanged == true )
  274.                     continue;
  275.  
  276.                 // Begin the scene.
  277.                 m_device->Clear( 0, NULL, viewer.viewClearFlags, 0, 1.0f, 0 );
  278.                 if( SUCCEEDED( m_device->BeginScene() ) )
  279.                 {
  280.                     // Render the scene, if there is a valid viewer.
  281.                     if( viewer.viewer != NULL )
  282.                         m_sceneManager->Render( elapsed, viewer.viewer->GetTranslation() );
  283.  
  284.                     // Render the current state, if there is one.
  285.                     if( m_currentState != NULL )
  286.                         m_currentState->Render();
  287.  
  288.                     // End the scene and present it.
  289.                     m_device->EndScene();
  290.                     m_device->Present( NULL, NULL, NULL, NULL );
  291.  
  292.                     // Keep track of the index of the current back buffer.
  293.                     if( ++m_currentBackBuffer == m_setup->totalBackBuffers + 1 )
  294.                         m_currentBackBuffer = 0;
  295.                 }
  296.             }
  297.         }
  298.     }
  299.  
  300.     // Destroy the engine.
  301.     SAFE_DELETE( g_engine );
  302. }
  303.  
  304. //-----------------------------------------------------------------------------
  305. // Returns the window handle.
  306. //-----------------------------------------------------------------------------
  307. HWND Engine::GetWindow()
  308. {
  309.     return m_window;
  310. }
  311.  
  312. //-----------------------------------------------------------------------------
  313. // Sets the deactive flag.
  314. //-----------------------------------------------------------------------------
  315. void Engine::SetDeactiveFlag( bool deactive )
  316. {
  317.     m_deactive = deactive;
  318. }
  319.  
  320. //-----------------------------------------------------------------------------
  321. // Returns the scale that the engine is currently running in.
  322. //-----------------------------------------------------------------------------
  323. float Engine::GetScale()
  324. {
  325.     return m_setup->scale;
  326. }
  327.  
  328. //-----------------------------------------------------------------------------
  329. // Returns a pointer to the Direct3D device.
  330. //-----------------------------------------------------------------------------
  331. IDirect3DDevice9 *Engine::GetDevice()
  332. {
  333.     return m_device;
  334. }
  335.  
  336. //-----------------------------------------------------------------------------
  337. // Returns a pointer to the display mode of the current Direct3D device.
  338. //-----------------------------------------------------------------------------
  339. D3DDISPLAYMODE *Engine::GetDisplayMode()
  340. {
  341.     return &m_displayMode;
  342. }
  343.  
  344. //-----------------------------------------------------------------------------
  345. // Returns a pointer to the sprite interface.
  346. //-----------------------------------------------------------------------------
  347. ID3DXSprite *Engine::GetSprite()
  348. {
  349.     return m_sprite;
  350. }
  351.  
  352. //-----------------------------------------------------------------------------
  353. // Adds a state to the engine.
  354. //-----------------------------------------------------------------------------
  355. void Engine::AddState( State *state, bool change )
  356. {
  357.     m_states->Add( state );
  358.  
  359.     if( change == false )
  360.         return;
  361.  
  362.     if( m_currentState != NULL )
  363.         m_currentState->Close();
  364.  
  365.     m_currentState = m_states->GetLast();
  366.     m_currentState->Load();
  367. }
  368.  
  369. //-----------------------------------------------------------------------------
  370. // Removes a state from the engine
  371. //-----------------------------------------------------------------------------
  372. void Engine::RemoveState( State *state )
  373. {
  374.     m_states->Remove( &state );
  375. }
  376.  
  377. //-----------------------------------------------------------------------------
  378. // Changes processing to the state with the specified ID.
  379. //-----------------------------------------------------------------------------
  380. void Engine::ChangeState( unsigned long id )
  381. {
  382.     // Iterate through the list of states and find the new state to change to.
  383.     m_states->Iterate( true );
  384.     while( m_states->Iterate() != NULL )
  385.     {
  386.         if( m_states->GetCurrent()->GetID() == id )
  387.         {
  388.             // Close the old state.
  389.             if( m_currentState != NULL )
  390.                 m_currentState->Close();
  391.  
  392.             // Let the sound system perform garbage collection.
  393.             m_soundSystem->GarbageCollection();
  394.  
  395.             // Set the new current state and load it.
  396.             m_currentState = m_states->GetCurrent();
  397.             m_currentState->Load();
  398.  
  399.             // Swap the back buffers until the first one is in the front.
  400.             while( m_currentBackBuffer != 0 )
  401.             {
  402.                 m_device->Present( NULL, NULL, NULL, NULL );
  403.  
  404.                 if( ++m_currentBackBuffer == m_setup->totalBackBuffers + 1 )
  405.                     m_currentBackBuffer = 0;
  406.             }
  407.  
  408.             // Indicate that the state has changed.
  409.             m_stateChanged = true;
  410.  
  411.             break;
  412.         }
  413.     }
  414. }
  415.  
  416. //-----------------------------------------------------------------------------
  417. // Returns a pointer to the current state.
  418. //-----------------------------------------------------------------------------
  419. State *Engine::GetCurrentState()
  420. {
  421.     return m_currentState;
  422. }
  423.  
  424. //-----------------------------------------------------------------------------
  425. // Returns a pointer to the script manager.
  426. //-----------------------------------------------------------------------------
  427. ResourceManager< Script > *Engine::GetScriptManager()
  428. {
  429.     return m_scriptManager;
  430. }
  431.  
  432. //-----------------------------------------------------------------------------
  433. // Returns a pointer to the material manager.
  434. //-----------------------------------------------------------------------------
  435. ResourceManager< Material > *Engine::GetMaterialManager()
  436. {
  437.     return m_materialManager;
  438. }
  439.  
  440. //-----------------------------------------------------------------------------
  441. // Returns a pointer to the mesh manager.
  442. //-----------------------------------------------------------------------------
  443. ResourceManager< Mesh > *Engine::GetMeshManager()
  444. {
  445.     return m_meshManager;
  446. }
  447.  
  448. //-----------------------------------------------------------------------------
  449. // Returns a pointer to the input object.
  450. //-----------------------------------------------------------------------------
  451. Input *Engine::GetInput()
  452. {
  453.     return m_input;
  454. }
  455.  
  456. //-----------------------------------------------------------------------------
  457. // Returns a pointer to the network object.
  458. //-----------------------------------------------------------------------------
  459. Network *Engine::GetNetwork()
  460. {
  461.     return m_network;
  462. }
  463.  
  464. //-----------------------------------------------------------------------------
  465. // Returns a pointer to the sound system.
  466. //-----------------------------------------------------------------------------
  467. SoundSystem *Engine::GetSoundSystem()
  468. {
  469.     return m_soundSystem;
  470. }
  471.  
  472. //-----------------------------------------------------------------------------
  473. // Returns a pointer to the scene manager.
  474. //-----------------------------------------------------------------------------
  475. SceneManager *Engine::GetSceneManager()
  476. {
  477.     return m_sceneManager;
  478. }