home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Direct3D / Tutorials / Tut04_Lights / Lights.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  11.6 KB  |  326 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Lights.cpp
  3. //
  4. // Desc: Rendering 3D geometry is much more interesting when dynamic lighting
  5. //       is added to the scene. To use lighting in D3D, you must create one or
  6. //       lights, setup a material, and make sure your geometry contains surface
  7. //       normals. Lights may have a position, a color, and be of a certain type
  8. //       such as directional (light comes from one direction), point (light
  9. //       comes from a specific x,y,z coordinate and radiates in all directions)
  10. //       or spotlight. Materials describe the surface of your geometry,
  11. //       specifically, how it gets lit (diffuse color, ambient color, etc.).
  12. //       Surface normals are part of a vertex, and are needed for the D3D's
  13. //       internal lighting calculations.
  14. //
  15. // Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
  16. //-----------------------------------------------------------------------------
  17. #include <d3dx8.h>
  18. #include <mmsystem.h>
  19.  
  20.  
  21.  
  22.  
  23. //-----------------------------------------------------------------------------
  24. // Global variables
  25. //-----------------------------------------------------------------------------
  26. LPDIRECT3D8             g_pD3D       = NULL; // Used to create the D3DDevice
  27. LPDIRECT3DDEVICE8       g_pd3dDevice = NULL; // Our rendering device
  28. LPDIRECT3DVERTEXBUFFER8 g_pVB        = NULL; // Buffer to hold vertices
  29.  
  30. // A structure for our custom vertex type. We added a normal, and omitted the
  31. // color (which is provided by the material)
  32. struct CUSTOMVERTEX
  33. {
  34.     D3DXVECTOR3 position; // The 3D position for the vertex
  35.     D3DXVECTOR3 normal;   // The surface normal for the vertex
  36. };
  37.  
  38. // Our custom FVF, which describes our custom vertex structure
  39. #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL)
  40.  
  41.  
  42.  
  43.  
  44. //-----------------------------------------------------------------------------
  45. // Name: InitD3D()
  46. // Desc: Initializes Direct3D
  47. //-----------------------------------------------------------------------------
  48. HRESULT InitD3D( HWND hWnd )
  49. {
  50.     // Create the D3D object.
  51.     if( NULL == ( g_pD3D = Direct3DCreate8( D3D_SDK_VERSION ) ) )
  52.         return E_FAIL;
  53.  
  54.     // Get the current desktop display mode, so we can set up a back
  55.     // buffer of the same format
  56.     D3DDISPLAYMODE d3ddm;
  57.     if( FAILED( g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
  58.         return E_FAIL;
  59.  
  60.     // Set up the structure used to create the D3DDevice. Since we are now
  61.     // using more complex geometry, we will create a device with a zbuffer.
  62.     D3DPRESENT_PARAMETERS d3dpp;
  63.     ZeroMemory( &d3dpp, sizeof(d3dpp) );
  64.     d3dpp.Windowed = TRUE;
  65.     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
  66.     d3dpp.BackBufferFormat = d3ddm.Format;
  67.     d3dpp.EnableAutoDepthStencil = TRUE;
  68.     d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
  69.  
  70.     // Create the D3DDevice
  71.     if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
  72.                                       D3DCREATE_SOFTWARE_VERTEXPROCESSING,
  73.                                       &d3dpp, &g_pd3dDevice ) ) )
  74.     {
  75.         return E_FAIL;
  76.     }
  77.  
  78.     // Turn off culling
  79.     g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
  80.  
  81.     // Turn on the zbuffer
  82.     g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
  83.  
  84.     return S_OK;
  85. }
  86.  
  87.  
  88.  
  89.  
  90. //-----------------------------------------------------------------------------
  91. // Name: InitGeometry()
  92. // Desc: Creates the scene geometry
  93. //-----------------------------------------------------------------------------
  94. HRESULT InitGeometry()
  95. {
  96.     // Create the vertex buffer.
  97.     if( FAILED( g_pd3dDevice->CreateVertexBuffer( 50*2*sizeof(CUSTOMVERTEX),
  98.                                                   0, D3DFVF_CUSTOMVERTEX,
  99.                                                   D3DPOOL_DEFAULT, &g_pVB ) ) )
  100.     {
  101.         return E_FAIL;
  102.     }
  103.  
  104.     // Fill the vertex buffer. We are algorithmically generating a cylinder
  105.     // here, including the normals, which are used for lighting.
  106.     CUSTOMVERTEX* pVertices;
  107.     if( FAILED( g_pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 ) ) )
  108.         return E_FAIL;
  109.     for( DWORD i=0; i<50; i++ )
  110.     {
  111.         FLOAT theta = (2*D3DX_PI*i)/(50-1);
  112.         pVertices[2*i+0].position = D3DXVECTOR3( sinf(theta),-1.0f, cosf(theta) );
  113.         pVertices[2*i+0].normal   = D3DXVECTOR3( sinf(theta), 0.0f, cosf(theta) );
  114.         pVertices[2*i+1].position = D3DXVECTOR3( sinf(theta), 1.0f, cosf(theta) );
  115.         pVertices[2*i+1].normal   = D3DXVECTOR3( sinf(theta), 0.0f, cosf(theta) );
  116.     }
  117.     g_pVB->Unlock();
  118.  
  119.     return S_OK;
  120. }
  121.  
  122.  
  123.  
  124.  
  125. //-----------------------------------------------------------------------------
  126. // Name: Cleanup()
  127. // Desc: Releases all previously initialized objects
  128. //-----------------------------------------------------------------------------
  129. VOID Cleanup()
  130. {
  131.     if( g_pVB != NULL )
  132.         g_pVB->Release();
  133.  
  134.     if( g_pd3dDevice != NULL )
  135.         g_pd3dDevice->Release();
  136.  
  137.     if( g_pD3D != NULL )
  138.         g_pD3D->Release();
  139. }
  140.  
  141.  
  142.  
  143. //-----------------------------------------------------------------------------
  144. // Name: SetupMatrices()
  145. // Desc: Sets up the world, view, and projection transform matrices.
  146. //-----------------------------------------------------------------------------
  147. VOID SetupMatrices()
  148. {
  149.     // For our world matrix, we will just leave it as the identity
  150.     D3DXMATRIX matWorld;
  151.     D3DXMatrixIdentity( &matWorld );
  152.     D3DXMatrixRotationX( &matWorld, timeGetTime()/500.0f );
  153.     g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  154.  
  155.     // Set up our view matrix. A view matrix can be defined given an eye point,
  156.     // a point to lookat, and a direction for which way is up. Here, we set the
  157.     // eye five units back along the z-axis and up three units, look at the
  158.     // origin, and define "up" to be in the y-direction.
  159.     D3DXMATRIX matView;
  160.     D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 3.0f,-5.0f ),
  161.                                   &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
  162.                                   &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );
  163.     g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
  164.  
  165.     // For the projection matrix, we set up a perspective transform (which
  166.     // transforms geometry from 3D view space to 2D viewport space, with
  167.     // a perspective divide making objects smaller in the distance). To build
  168.     // a perpsective transform, we need the field of view (1/4 pi is common),
  169.     // the aspect ratio, and the near and far clipping planes (which define at
  170.     // what distances geometry should be no longer be rendered).
  171.     D3DXMATRIX matProj;
  172.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );
  173.     g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  174. }
  175.  
  176.  
  177.  
  178.  
  179. //-----------------------------------------------------------------------------
  180. // Name: SetupLights()
  181. // Desc: Sets up the lights and materials for the scene.
  182. //-----------------------------------------------------------------------------
  183. VOID SetupLights()
  184. {
  185.     // Set up a material. The material here just has the diffuse and ambient
  186.     // colors set to yellow. Note that only one material can be used at a time.
  187.     D3DMATERIAL8 mtrl;
  188.     ZeroMemory( &mtrl, sizeof(D3DMATERIAL8) );
  189.     mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
  190.     mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
  191.     mtrl.Diffuse.b = mtrl.Ambient.b = 0.0f;
  192.     mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
  193.     g_pd3dDevice->SetMaterial( &mtrl );
  194.  
  195.     // Set up a white, directional light, with an oscillating direction.
  196.     // Note that many lights may be active at a time (but each one slows down
  197.     // the rendering of our scene). However, here we are just using one. Also,
  198.     // we need to set the D3DRS_LIGHTING renderstate to enable lighting
  199.     D3DXVECTOR3 vecDir;
  200.     D3DLIGHT8 light;
  201.     ZeroMemory( &light, sizeof(D3DLIGHT8) );
  202.     light.Type       = D3DLIGHT_DIRECTIONAL;
  203.     light.Diffuse.r  = 1.0f;
  204.     light.Diffuse.g  = 1.0f;
  205.     light.Diffuse.b  = 1.0f;
  206.     vecDir = D3DXVECTOR3(cosf(timeGetTime()/350.0f),
  207.                          1.0f,
  208.                          sinf(timeGetTime()/350.0f) );
  209.     D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir );
  210.     light.Range       = 1000.0f;
  211.     g_pd3dDevice->SetLight( 0, &light );
  212.     g_pd3dDevice->LightEnable( 0, TRUE );
  213.     g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  214.  
  215.     // Finally, turn on some ambient light.
  216.     g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00202020 );
  217. }
  218.  
  219.  
  220.  
  221.  
  222. //-----------------------------------------------------------------------------
  223. // Name: Render()
  224. // Desc: Draws the scene
  225. //-----------------------------------------------------------------------------
  226. VOID Render()
  227. {
  228.     // Clear the backbuffer and the zbuffer
  229.     g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
  230.                          D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
  231.  
  232.     // Begin the scene
  233.     g_pd3dDevice->BeginScene();
  234.  
  235.     // Setup the lights and materials
  236.     SetupLights();
  237.  
  238.     // Setup the world, view, and projection matrices
  239.     SetupMatrices();
  240.  
  241.     // Render the vertex buffer contents
  242.     g_pd3dDevice->SetStreamSource( 0, g_pVB, sizeof(CUSTOMVERTEX) );
  243.     g_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX );
  244.     g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2*50-2 );
  245.  
  246.     // End the scene
  247.     g_pd3dDevice->EndScene();
  248.  
  249.     // Present the backbuffer contents to the display
  250.     g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  251. }
  252.  
  253.  
  254.  
  255.  
  256. //-----------------------------------------------------------------------------
  257. // Name: MsgProc()
  258. // Desc: The window's message handler
  259. //-----------------------------------------------------------------------------
  260. LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  261. {
  262.     switch( msg )
  263.     {
  264.         case WM_DESTROY:
  265.             PostQuitMessage( 0 );
  266.             return 0;
  267.     }
  268.  
  269.     return DefWindowProc( hWnd, msg, wParam, lParam );
  270. }
  271.  
  272.  
  273.  
  274.  
  275. //-----------------------------------------------------------------------------
  276. // Name: WinMain()
  277. // Desc: The application's entry point
  278. //-----------------------------------------------------------------------------
  279. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  280. {
  281.     // Register the window class
  282.     WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
  283.                       GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
  284.                       "D3D Tutorial", NULL };
  285.     RegisterClassEx( &wc );
  286.  
  287.     // Create the application's window
  288.     HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial 04: Lights",
  289.                               WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
  290.                               GetDesktopWindow(), NULL, wc.hInstance, NULL );
  291.  
  292.     // Initialize Direct3D
  293.     if( SUCCEEDED( InitD3D( hWnd ) ) )
  294.     {
  295.         // Create the geometry
  296.         if( SUCCEEDED( InitGeometry() ) )
  297.         {
  298.             // Show the window
  299.             ShowWindow( hWnd, SW_SHOWDEFAULT );
  300.             UpdateWindow( hWnd );
  301.  
  302.             // Enter the message loop
  303.             MSG msg;
  304.             ZeroMemory( &msg, sizeof(msg) );
  305.             while( msg.message!=WM_QUIT )
  306.             {
  307.                 if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
  308.                 {
  309.                     TranslateMessage( &msg );
  310.                     DispatchMessage( &msg );
  311.                 }
  312.                 else
  313.                     Render();
  314.             }
  315.         }
  316.     }
  317.  
  318.     // Clean up everything and exit the app
  319.     Cleanup();
  320.     UnregisterClass( "D3D Tutorial", wc.hInstance );
  321.     return 0;
  322. }
  323.  
  324.  
  325.  
  326.