//-----------------------------------------------------------------------------
// Name: dx9_spot_light.cpp
// Author: Kevin Harris (kevin@codesampler.com)
// Last Modified: 02/17/05
// Description: This sample demonstrates how to setup a spot light with
// Direct3D. The sample also demonstrates how the tessellation
// or triangle count of a mesh effects lighting.
//
// Control Keys: v - Decrease the mesh's tessellation or vertex count
// V - Increase the mesh's tessellation or vertex count
// w - Toggle wire-frame mode
//
// r - Decrease Range
// R - Increase Range
// t - Decrease Theta
// T - Increase Theta
// p - Decrease Phi
// P - Increase Phi
// f - Decrease Falloff
// F - Increase Falloff
// F1 - Decrease Attenuation0
// F2 - Increase Attenuation0
// F3 - Decrease Attenuation1
// F4 - Increase Attenuation1
// F5 - Decrease Attenuation2
// F6 - Increase Attenuation2
//
// Up - Move the spot light up
// Down - Move the spot light down
// Left - Swing the spot to the left
// Right - Swing the spot to the right
//
// NOTE: Please refer to the DirectX 9.0c Documentation for the more
// information concerning the Attenuation, Theta, Phi, and Falloff
// controls.
//-----------------------------------------------------------------------------
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include <d3d9.h>
#include <d3dx9.h>
#include "resource.h"
//-----------------------------------------------------------------------------
// GLOBALS
//-----------------------------------------------------------------------------
HWND g_hWnd = NULL;
LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pMeshVertices = NULL; // Vertex buffer for our custom made mesh
LPD3DXMESH g_pConeMesh = NULL; // A mesh to represent a spot light
D3DLIGHT9 g_light0;
D3DMATERIAL9 g_meshMaterial;
D3DMATERIAL9 g_coneMaterial;
bool g_bRenderInWireFrame = false;
float g_fLightPositionY = 3.0f;
float g_fLightDirectionX = 0.0f;
float g_fAttenuation0 = 0.0f;
float g_fAttenuation1 = 0.5f;
float g_fAttenuation2 = 0.0f;
float g_fRange = 10.0f;
float g_fTheta = 0.5f;
float g_fPhi = 1.0f;
float g_fFalloff = 1.0f;
int g_nMeshVertCount = 0;
int g_nNumVerts = 64;
#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE )
struct Vertex
{
float x, y, z; // Position of vertex in 3D space
float nx, ny, nz; // Normal for lighting calculations
DWORD diffuse; // Diffuse color of vertex
};
//-----------------------------------------------------------------------------
// PROTOTYPES
//-----------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow);
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void init(void);
void shutDown(void);
void render(void);
void initLighting(void);
int createSimpleMesh(int nNumVertsAlongX, int nNumVertsAlongZ,
float fMeshLengthAlongX, float fMeshLengthAlongZ);
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
WNDCLASSEX winClass;
MSG uMsg;
memset(&uMsg,0,sizeof(uMsg));
winClass.lpszClassName = "MY_WINDOWS_CLASS";
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc = WindowProc;
winClass.hInstance = hInstance;
winClass.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_DIRECTX_ICON);
winClass.hIconSm = LoadIcon(hInstance, (LPCTSTR)IDI_DIRECTX_ICON);
winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
if(!RegisterClassEx( &winClass) )
return E_FAIL;
g_hWnd = CreateWindowEx( NULL, "MY_WINDOWS_CLASS", "Direct3D (DX9) - Spot Light",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0, 640, 480, NULL, NULL, hInstance, NULL );
if( g_hWnd == NULL )
return E_FAIL;
ShowWindow( g_hWnd, nCmdShow );
UpdateWindow( g_hWnd );
init();
while( uMsg.message != WM_QUIT )
{
if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &uMsg );
DispatchMessage( &uMsg );
}
else
render();
}
shutDown();
UnregisterClass( "MY_WINDOWS_CLASS", winClass.hInstance );
return uMsg.wParam;
}
//-----------------------------------------------------------------------------
// Name: WindowProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT CALLBACK WindowProc( HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam )
{
switch( msg )
{
case WM_CHAR:
{
switch( wParam )
{
case 'v':
g_nNumVerts -= 1;
// Don't let the mesh's resolution get too low!
if( g_nNumVerts <= 1 )
g_nNumVerts = 2;
// Release the old mesh so we can create a new one.
if( g_pMeshVertices != NULL )
g_pMeshVertices->Release();
g_nMeshVertCount = createSimpleMesh( g_nNumVerts, g_nNumVerts, 10.0f, 10.0f );
break;
case 'V':
g_nNumVerts += 1;
// Release the old mesh so we can create a new one.
if( g_pMeshVertices != NULL )
g_pMeshVertices->Release();
g_nMeshVertCount = createSimpleMesh( g_nNumVerts, g_nNumVerts, 10.0f, 10.0f );
break;
case 'r':
g_fRange -= 1.0f;
break;
case 'R':
g_fRange += 1.0f;
break;
case 't':
g_fTheta -= 0.01f;
if( g_fTheta < 0.0f )
g_fTheta = 0.0f;
break;
case 'T':
g_fTheta += 0.01f;
break;
case 'p':
g_fPhi -= 0.01f;
if( g_fPhi < 0.0f )
g_fPhi = 0.0f;
break;
case 'P':
g_fPhi += 0.01f;
break;
case 'f':
g_fFalloff -= 0.01f;
if( g_fFalloff < 0.0f )
g_fFalloff = 0.0f;
break;
case 'F':
g_fFalloff += 0.01f;
break;
case 'w':
case 'W':
g_bRenderInWireFrame = !g_bRenderInWireFrame;
if( g_bRenderInWireFra