#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>

// Constants
const int CULLCOUNTERCLOCKWISE = 0;
const int CULLCLOCKWISE = 1;
const int CULLNONE = 2;

// Function prototypes.
LRESULT WINAPI WndProc(HWND hWnd, UINT msg,
    WPARAM wParam, LPARAM lParam);
void InitApp(HINSTANCE hInstance);
void RunApp();
void CleanUpApp();
void RegisterWindowClass(HINSTANCE hInstance);
void CreateAppWindow(HINSTANCE hInstance);
WPARAM StartMessageLoop();
void HandleKeys(WPARAM wParam);
HRESULT InitDirect3D();
HRESULT CreateDevice();
HRESULT SetRenderingStates();
HRESULT LoadTextures();
HRESULT LoadBackgroundBitmap();
void CleanUpDirect3D();
void Render();
HRESULT InitVertices();
VOID SetWorldTransformation(float fXRot, float fYRot, float fZRot, 
        float fXTrans, float fYTrans, float fZTrans,
        float fXScale, float fYScale, float fZScale);
void SetViewTransformation();
void SetProjectionTransformation();
void InitLights();
void RenderTransparentCube();
void RenderSign();
void RenderCubeA();
void RenderCubeB();
void RenderCubeC();
void RenderStarCube();
void RenderTransparentRectangles();
void UpdateAnimation();
void RestoreDefaultSettings();
void SetVariableRenderStates();
void DisplayBackgroundImage();

// Global variables.
HWND g_hWnd;
IDirect3D9* g_pDirect3D = NULL;
IDirect3DDevice9* g_pDirect3DDevice = NULL;
IDirect3DVertexBuffer9* g_pVertexBuf = NULL;
IDirect3DVertexBuffer9* g_pTransparentSquareVertexBuf = NULL;
IDirect3DTexture9* g_pTransparentTexture = NULL;
IDirect3DTexture9* g_pTextureA = NULL;
IDirect3DTexture9* g_pTextureB = NULL;
IDirect3DTexture9* g_pTextureC = NULL;
IDirect3DTexture9* g_pTextureStar = NULL;
IDirect3DTexture9* g_pTexturePillar = NULL;
IDirect3DTexture9* g_pTextureWelcome = NULL;
IDirect3DTexture9* g_pTextureWelcome1 = NULL;
IDirect3DTexture9* g_pTextureWelcome2 = NULL;
IDirect3DTexture9* g_pTransparentSquareTexture = NULL;
IDirect3DSurface9* g_pBackgroundSurface = NULL;
IDirect3DSurface9* g_pBackBuffer = NULL;
FLOAT g_fZDistance = -12.0f;
FLOAT g_fZLookAt = 100.0f;
BOOL g_bFogOn = TRUE;
BOOL g_bAlphaBlendingOn = TRUE;
BOOL g_bZBufferingOn = TRUE;
INT g_iCullingMode = CULLNONE;
BOOL g_bLightingOn = TRUE;
INT g_iNumTriangles;
FLOAT g_fLightPosition = 15.0f;
FLOAT g_fAmbientLight = 0.4f;
FLOAT g_fMaterialRed = 1.0f;
FLOAT g_fMaterialGreen = 1.0f;
FLOAT g_fMaterialBlue = 1.0f;
BOOL g_bShowBackground = TRUE;
FLOAT g_fFogDensity = 0.02f;
BOOL g_bUseTextures = TRUE;
FLOAT g_fSignTranslation = -3.0;

// Custom vertices for primitives using vertex alpha.
struct TRANSCUSTOMVERTEXSTRUCT
{
    D3DVECTOR coords;
    D3DVECTOR normal;
    DWORD dwColor;
    float tu, tv;
};

// Custom vertices for primitives NOT using vertex alpha blending.
struct CUSTOMVERTEXSTRUCT
{
    D3DVECTOR coords;
    D3DVECTOR normal;
	float tu, tv;
};

//////////////////////////////////////////////////////
// WinMain()
//////////////////////////////////////////////////////
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, INT)
{
	InitApp(hInstance);
	RunApp();
    CleanUpApp();
    return 0;
}

//////////////////////////////////////////////////////
// InitApp()
//////////////////////////////////////////////////////
void InitApp(HINSTANCE hInstance)
{
    RegisterWindowClass(hInstance);
    CreateAppWindow(hInstance);
    ShowWindow(g_hWnd, SW_SHOWDEFAULT);
    UpdateWindow(g_hWnd);
	SetTimer(g_hWnd, 1, 500, NULL);
}

//////////////////////////////////////////////////////
// RunApp()
//////////////////////////////////////////////////////
void RunApp()
{
    if (SUCCEEDED(InitDirect3D()))
    {
        InitVertices();
        WPARAM result = StartMessageLoop();
    }
}

//////////////////////////////////////////////////////
// CleanUpApp()
//////////////////////////////////////////////////////
void CleanUpApp()
{
	KillTimer(g_hWnd, 1);
    CleanUpDirect3D();
}

//////////////////////////////////////////////////////
// RegisterWindowClass()
//////////////////////////////////////////////////////
void RegisterWindowClass(HINSTANCE hInstance)
{
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0; 
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = (HCURSOR)LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "D3DDemoApp";
    wc.hIconSm = NULL;

    RegisterClassEx(&wc);
}

//////////////////////////////////////////////////////
// CreateAppWindow()
//////////////////////////////////////////////////////
void CreateAppWindow(HINSTANCE hInstance)
{
    g_hWnd = CreateWindowEx(
        NULL,
        "D3DDemoApp",
        "Direct3D Demo Application", 
        WS_OVERLAPPEDWINDOW,
        100,
        100,
        800,
        600,
        GetDesktopWindow(),
        NULL,
        hInstance,
        NULL);
}

//////////////////////////////////////////////////////
// StartMessageLoop()
//////////////////////////////////////////////////////
WPARAM StartMessageLoop()
{
    MSG msg;
    while(1)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            // Use idle time here.
            Render();
        }
    }
    return msg.wParam;
}

//////////////////////////////////////////////////////
// WndProc()
//////////////////////////////////////////////////////
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_CREATE:
        return 0;

    case WM_DESTROY:
        PostQuitMessage( 0 );
        return 0;

    case WM_PAINT:
        ValidateRect(g_hWnd, NULL);
        return 0;

    case WM_TIMER:
        UpdateAnimation();
        return 0;

    case WM_KEYDOWN:
		HandleKeys(wParam);
		return 0;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

//////////////////////////////////////////////////////
// HandleKeys()
//////////////////////////////////////////////////////
void HandleKeys(WPARAM wParam)
{
    switch(wParam)
    {
    case VK_ESCAPE:
        PostQuitMessage(WM_QUIT);
        break;
	case VK_DOWN:
		g_fZDistance -= 0.2f;
		if (g_fZDistance < -6.0f)
			g_fZLookAt = 100.0;
		break;
	case VK_UP:
		g_fZDistance += 0.2f;
		if (g_fZDistance > 15)
			g_fZLookAt = -100.0f;
		break;
	case VK_SPACE:
		g_fZLookAt = -g_fZLookAt;
		break;
	case 65: // A
		g_bAlphaBlendingOn = !g_bAlphaBlendingOn;
		break;
	case 66: // B
		if ((g_fMaterialBlue += 0.01f) > 1.0f)
			g_fMaterialBlue = 0.0f;
		break;
	case 67: // C
		++g_iCullingMode;
		if (g_iCullingMode > CULLNONE)
			g_iCullingMode = CULLCOUNTERCLOCKWISE;
		break;
	case 68: // D
		RestoreDefaultSettings();
		break;
	case 69: // E
		if ((g_fFogDensity += 0.01f) > 1.0f)
			g_fFogDensity = 0.02f;
		break;
	case 70: // F
		g_bFogOn = !g_bFogOn;
		break;
	case 71: // G
		if ((g_fMaterialGreen += 0.01f) > 1.0f)
			g_fMaterialGreen = 0.0f;
		break;
	case 75: // K
		g_bShowBackground = !g_bShowBackground;
		break;
	case 76: // L
		g_bLightingOn = !g_bLightingOn;
		break;
	case 77: // M
		if ((g_fAmbientLight += 0.01f) > 1.0f)
			g_fAmbientLight = 0.0f;
		break;
	case 80: // P
		if ((g_fLightPosition += 0.2f) > 15)
			g_fLightPosition = 0.0f;
		break;
	case 81: // Q
		g_fSignTranslation += 0.2f;
		break;
	case 82: // R
		if ((g_fMaterialRed += 0.01f) > 1.0f)
			g_fMaterialRed = 0.0f;
		break;
	case 84: // T
		g_bUseTextures = !g_bUseTextures;
		break;
	case 87: // W
		g_fSignTranslation -= 0.2f;
		break;
	case 90: // Z
		g_bZBufferingOn = !g_bZBufferingOn;
		break;
    }
}

//////////////////////////////////////////////////////
// RestoreDefaultSettings()
//////////////////////////////////////////////////////
void RestoreDefaultSettings()
{
	g_bFogOn = TRUE;
	g_bAlphaBlendingOn = TRUE;
	g_bZBufferingOn = TRUE;
	g_iCullingMode = CULLNONE;
	g_bLightingOn = TRUE;
	g_iNumTriangles;
	g_fLightPosition = 15.0f;
	g_fAmbientLight = 0.4f;
	g_fMaterialRed = 1.0f;
	g_fMaterialGreen = 1.0f;
	g_fMaterialBlue = 1.0f;
    g_bShowBackground = TRUE;
    g_fFogDensity = 0.02f;
    g_bUseTextures = TRUE;
	g_fSignTranslation = -3.0f;
}

//////////////////////////////////////////////////////
// InitDirect3D()
//////////////////////////////////////////////////////
HRESULT InitDirect3D()
{
	// Create the main Direct3D object.
    if((g_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
	{
        MessageBox(g_hWnd, "Couldn't create main Direct3D object.", 
			"FinalApp - Error", MB_OK | MB_ICONEXCLAMATION);
        return E_FAIL;
	}

	// Get the current display mode.
	D3DDISPLAYMODE d3ddisplaymode;
    if (FAILED(g_pDirect3D->GetAdapterDisplayMode(
		    D3DADAPTER_DEFAULT, &d3ddisplaymode)))
	{
        MessageBox(g_hWnd, "Couldn't determine display mode.", 
			"FinalApp - Error", MB_OK | MB_ICONEXCLAMATION);
        return E_FAIL;
	}

	// Determine whether the display mode is compatible with this app.
    if (d3ddisplaymode.Format != D3DFMT_X8R8G8B8)
	{
        MessageBox(g_hWnd, "This application requires the 32-bit display mode.", 
			"FinalApp - Error", MB_OK | MB_ICONEXCLAMATION);
        return E_FAIL;
	}

	// Create the Direct3D device.
	if (FAILED(CreateDevice()))
	{
        MessageBox(g_hWnd, "Couldn't create main Direct3D device.", 
			"FinalApp - Error", MB_OK | MB_ICONEXCLAMATION);
        return E_FAIL;
	}

    // Set global rendering states.
    if (FAILED(SetRenderingStates()))
    {
        MessageBox(g_hWnd, "Couldn't set rendering states.", 
			"FinalApp - Error", MB_OK | MB_ICONEXCLAMATION);
        PostQuitMessage(WM_QUIT);
    }

    // Load the textures.
    if (FAILED(LoadTextures()))
    {
        MessageBox(g_hWnd, "Couldn't load textures.", 
			"FinalApp - Error", MB_OK | MB_ICONEXCLAMATION);
        PostQuitMessage(WM_QUIT);
    }

	// Set first texture for animated sign.
	g_pTextureWelcome = g_pTextureWelcome1;

    // Load background bitmap.
    if (FAILED(LoadBackgroundBitmap()))
    {
        MessageBox(g_hWnd, "Couldn't load background bitmap.", 
			"FinalApp - Error", MB_OK | MB_ICONEXCLAMATION);
        PostQuitMessage(WM_QUIT);
    }

    // Get a pointer to the back buffer.
    if (FAILED(g_pDirect3DDevice->GetBackBuffer(0, 0,
        D3DBACKBUFFER_TYPE_MONO, &g_pBackBuffer)))
    {
        MessageBox(g_hWnd, "Couldn't acquire back buffer.", 
			"FinalApp - Error", MB_OK | MB_ICONEXCLAMATION);
        PostQuitMessage(WM_QUIT);
    }

	return D3D_OK;
}

//////////////////////////////////////////////////////
// CreateDevice()
//////////////////////////////////////////////////////
HRESULT CreateDevice()
{
    D3DPRESENT_PARAMETERS D3DPresentParams;
    ZeroMemory(&D3DPresentParams, sizeof(D3DPRESENT_PARAMETERS));
    D3DPresentParams.Windowed = TRUE;
    D3DPresentParams.BackBufferFormat = D3DFMT_UNKNOWN;
    D3DPresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
    D3DPresentParams.hDeviceWindow = g_hWnd;
    D3DPresentParams.EnableAutoDepthStencil = TRUE;
    D3DPresentParams.AutoDepthStencilFormat = D3DFMT_D16;

    HRESULT hResult = g_pDirect3D->CreateDevice(D3DADAPTER_DEFAULT, 
            D3DDEVTYPE_HAL, g_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
            &D3DPresentParams, &g_pDirect3DDevice);
	return hResult;
}

//////////////////////////////////////////////////////
// SetRenderingStates()
//////////////////////////////////////////////////////
HRESULT SetRenderingStates()
{
	// Set up Alpha blending. NOTE: Enabling alpha blending,
	// is controlled by the A-key switch and the
	// g_bAlphaBlendingOn variable. See Render().
	if (FAILED(g_pDirect3DDevice->SetRenderState(D3DRS_SRCBLEND, 
		    D3DBLEND_SRCALPHA)))
		return E_FAIL;
	if (FAILED(g_pDirect3DDevice->SetRenderState(D3DRS_DESTBLEND, 
		    D3DBLEND_INVSRCALPHA)))
		return E_FAIL;

	// Setup the application for vertex alpha blending.
	if (FAILED(g_pDirect3DDevice->SetRenderState(
		    D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1)))
		return E_FAIL;

	// Set up alpha testing.
	if (FAILED(g_pDirect3DDevice->SetRenderState(D3DRS_ALPHAREF, 96)))
		return E_FAIL;
	if (FAILED(g_pDirect3DDevice->SetRenderState(D3DRS_ALPHAFUNC, 
		    D3DCMP_GREATEREQUAL)))
		return E_FAIL;

	// Set up fog, except for enabling fog, which is controlled 
	// by the F-key switch and the g_bFogOn variable, and fog
	// color, which is controlled by the K-key switch and
	// the g_bShowBackground variable. See Render().
    if (FAILED(g_pDirect3DDevice->
		    SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_EXP2)))
		return E_FAIL;

	return D3D_OK;
}

//////////////////////////////////////////////////////
// LoadTextures()
//////////////////////////////////////////////////////
HRESULT LoadTextures()
{
	// Load texture with fully transparent areas (color key).
	if (FAILED(D3DXCreateTextureFromFileEx(g_pDirect3DDevice, 
		    "texture.bmp", D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, 
		    D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE, 
		    D3DX_FILTER_TRIANGLE, D3DCOLOR_RGBA(255,0,0,255), 
			NULL, NULL, &g_pTransparentTexture)))
		return E_FAIL;

	// Load remaining textures.
	if (FAILED(D3DXCreateTextureFromFile(g_pDirect3DDevice, 
		    "Texture_A.bmp", &g_pTextureA)))
		return E_FAIL;
	if (FAILED(D3DXCreateTextureFromFile(g_pDirect3DDevice, 
		    "Texture_B.bmp", &g_pTextureB)))
		return E_FAIL;
	if (FAILED(D3DXCreateTextureFromFile(g_pDirect3DDevice, 
		    "Texture_C.bmp", &g_pTextureC)))
		return E_FAIL;
	if (FAILED(D3DXCreateTextureFromFile(g_pDirect3DDevice, 
		    "Texture_Star.bmp", &g_pTextureStar)))
		return E_FAIL;
    if (FAILED(D3DXCreateTextureFromFile(g_pDirect3DDevice, 
            "texture03.bmp", &g_pTransparentSquareTexture)))
		return E_FAIL;
    if (FAILED(D3DXCreateTextureFromFile(g_pDirect3DDevice, 
            "Texture_Pillar.bmp", &g_pTexturePillar)))
		return E_FAIL;
    if (FAILED(D3DXCreateTextureFromFile(g_pDirect3DDevice, 
            "Texture_Welcome1.bmp", &g_pTextureWelcome1)))
		return E_FAIL;
    if (FAILED(D3DXCreateTextureFromFile(g_pDirect3DDevice, 
            "Texture_Welcome2.bmp", &g_pTextureWelcome2)))
		return E_FAIL;

	return D3D_OK;
}

//////////////////////////////////////////////////////
// LoadBackgroundBitmap()
//////////////////////////////////////////////////////
HRESULT LoadBackgroundBitmap()
{
	// Create a surface for the background bitmap.
    if (FAILED(g_pDirect3DDevice->CreateOffscreenPlainSurface(800, 600, 
            D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &g_pBackgroundSurface, NULL)))
		return E_FAIL;

	// Load the background bitmap into the surface.
    if (FAILED(D3DXLoadSurfaceFromFile(g_pBackgroundSurface, NULL, NULL,
            "Background.bmp", NULL, D3DX_DEFAULT, 0, NULL)))
		return E_FAIL;

	return D3D_OK;
}

//////////////////////////////////////////////////////
// CleanUpDirect3D()
//////////////////////////////////////////////////////
void CleanUpDirect3D()
{
    if (g_pBackgroundSurface)
    {
        g_pBackgroundSurface->Release(); 
        g_pBackgroundSurface = NULL;
    }
    if (g_pVertexBuf)
    {
        g_pVertexBuf->Release(); 
        g_pVertexBuf = NULL;
    }
    if (g_pTransparentSquareVertexBuf)
    {
        g_pTransparentSquareVertexBuf->Release(); 
        g_pTransparentSquareVertexBuf = NULL;
    }
    if (g_pTransparentSquareTexture)
    {
        g_pTransparentSquareTexture->Release();
        g_pTransparentSquareTexture = NULL;
    }
    if (g_pTextureWelcome2)
    {
        g_pTextureWelcome2->Release();
        g_pTextureWelcome2 = NULL;
    }
    if (g_pTextureWelcome1)
    {
        g_pTextureWelcome1->Release();
        g_pTextureWelcome1 = NULL;
    }
    if (g_pTexturePillar)
    {
        g_pTexturePillar->Release();
        g_pTexturePillar = NULL;
    }
    if (g_pTextureStar)
    {
        g_pTextureStar->Release();
        g_pTextureStar = NULL;
    }
    if (g_pTextureC)
    {
        g_pTextureC->Release();
        g_pTextureC = NULL;
    }
    if (g_pTextureB)
    {
        g_pTextureB->Release();
        g_pTextureB = NULL;
    }
    if (g_pTextureA)
    {
        g_pTextureA->Release();
        g_pTextureA = NULL;
    }
    if (g_pTransparentTexture)
    {
        g_pTransparentTexture->Release();
        g_pTransparentTexture = NULL;
    }
    if (g_pBackBuffer)
    {
        g_pBackBuffer->Release();
        g_pBackBuffer = NULL;
    }
    if (g_pDirect3DDevice)
    {
        g_pDirect3DDevice->Release();
        g_pDirect3DDevice = NULL;
    }
    if (g_pDirect3D)
    {
        g_pDirect3D->Release();
        g_pDirect3D = NULL;
    }
}

//////////////////////////////////////////////////////
// UpdateAnimation()
//////////////////////////////////////////////////////
VOID UpdateAnimation()
{
	static bool bFirstFrame = TRUE;
	if (bFirstFrame)
		g_pTextureWelcome = g_pTextureWelcome1;
	else
		g_pTextureWelcome = g_pTextureWelcome2;
	bFirstFrame = !bFirstFrame;
}

//////////////////////////////////////////////////////
// Render()
//////////////////////////////////////////////////////
VOID Render()
{
	// Clear the target surface.
    g_pDirect3DDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
        D3DCOLOR_XRGB(0,0,0), 1.0f, 0);

	DisplayBackgroundImage();
	SetVariableRenderStates();

	// Render the 3D scene.
    if(SUCCEEDED(g_pDirect3DDevice->BeginScene()))
    {
        InitLights();
		SetViewTransformation();
		SetProjectionTransformation();
		RenderTransparentCube();
		RenderSign();
        RenderCubeA();
        RenderCubeB();
        RenderCubeC();
		RenderStarCube();
		RenderTransparentRectangles();
		g_pDirect3DDevice->EndScene();
    }

	// Display the newly rendered scene.
    g_pDirect3DDevice->Present( NULL, NULL, NULL, NULL );
}

//////////////////////////////////////////////////////
// DisplayBackgroundImage()
//////////////////////////////////////////////////////
void DisplayBackgroundImage()
{
	// Set up source and destination rectangles for the background blit.
	RECT SrcRect;
	RECT DstRect;
    SrcRect.left = 0;     SrcRect.right = 799;
    SrcRect.top = 0;      SrcRect.bottom = 599;
    DstRect.left = 0;     DstRect.top = 0;
    DstRect.right = 792;  DstRect.bottom = 566;
    
	// Blit the background image to the target surface.
	if (g_bShowBackground)
	    g_pDirect3DDevice->StretchRect(g_pBackgroundSurface,
		    &SrcRect, g_pBackBuffer, &DstRect, D3DTEXF_NONE);
}

//////////////////////////////////////////////////////
// SetVariableRenderingStates()
//////////////////////////////////////////////////////
void SetVariableRenderStates()
{
	// Set fog color based on whether background is displayed.
	if (g_bShowBackground)
	    g_pDirect3DDevice->SetRenderState(D3DRS_FOGCOLOR,
		    D3DXCOLOR(255,255,255,255));
	else
        g_pDirect3DDevice->SetRenderState(D3DRS_FOGCOLOR,
		    D3DXCOLOR(0,0,0,0));

	// Turn Z-buffering on and off.
	g_pDirect3DDevice->SetRenderState(D3DRS_ZENABLE, g_bZBufferingOn);

	// Turn back-face culling on or off.
	if (g_iCullingMode == CULLCOUNTERCLOCKWISE)
	    g_pDirect3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
	else if (g_iCullingMode == CULLCLOCKWISE)
		g_pDirect3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
	else if (g_iCullingMode == CULLNONE)
		g_pDirect3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

	// Turn fog on or off.
	g_pDirect3DDevice->SetRenderState(D3DRS_FOGENABLE, g_bFogOn);

	// Set fog density.
    g_pDirect3DDevice->SetRenderState(D3DRS_FOGDENSITY, 
		    *(DWORD *)(&g_fFogDensity));
}

//////////////////////////////////////////////////////
// RenderTransparentCube()
//////////////////////////////////////////////////////
void RenderTransparentCube()
{
    static float angle = 0.0f;
    angle += 0.01f;
    SetWorldTransformation(
		0.0f, angle, 0.0f, /* Rotations    */
		0.0f, 0.0f, 1.0f,  /* Translations */
		1.0f, 1.0f, 1.0f); /* Scaling      */
    g_pDirect3DDevice->SetStreamSource(0, g_pVertexBuf, 0, 
        sizeof(CUSTOMVERTEXSTRUCT));

	// Set the first color argument to the texture color.
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);

	// Set the second color argument to be the output of the previous stage.
	// Because there is no previous stage, this argument results in
	// the same value as the D3DTA_DIFFUSE setting, which is the vertex
	// diffuse color or, lacking that, the default color of 0xFFFFFFFF.
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);

	// Set the color operation to multiply the colors (which is the default).
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);

	// Set the alpha argument to the texture, because that's where the
	// D3DXCreateTextureFromFileEx() function placed the alpha data.
	g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);

	// Set the operation to use for alpha blending. In this case, use the stage's
	// first argument (the texture color) as the output. Thanks to the
	// D3DXCreateTextureFromFileEx() function, transparent areas will
	// have the transparent-black color and so won't appear. Other colors pass
	// through exactly as they are.
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

	// Turn alpha blending on or off, based on the g_bAlphaBlendingOn variable.
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, g_bAlphaBlendingOn);

	// Turn on alpha testing.
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);

	// Set the texture to use.
	if (g_bUseTextures)
	    g_pDirect3DDevice->SetTexture(0, g_pTransparentTexture);
	else
	    g_pDirect3DDevice->SetTexture(0, NULL);

	// Set the vertex format, and draw the cube.
	g_pDirect3DDevice->SetFVF(D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1);
    g_pDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 
        0, g_iNumTriangles);
}

//////////////////////////////////////////////////////
// RenderSign()
//////////////////////////////////////////////////////
void RenderSign()
{
	// Set the first color argument to the texture color.
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);

	// Set the second color argument to be the output of the previous stage.
	// Because there is no previous stage, this argument results in
	// the same value as the D3DTA_DIFFUSE setting, which is the vertex
	// diffuse color or, lacking that, the default color of 0xFFFFFFFF.
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);

	// Set the color operation to multiply the colors (which is the default).
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);

	// No alpha blending or testing.
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

	// Render the first pillar.
	SetWorldTransformation(
		0.0f, 0.0f, 0.0f,                /* Rotations    */
		-2.5f, 0.0f, g_fSignTranslation, /* Translations */
		1.0f, 5.0f, 1.0f);               /* Scaling      */
    g_pDirect3DDevice->SetStreamSource(0, g_pVertexBuf, 0, 
        sizeof(CUSTOMVERTEXSTRUCT));

	if (g_bUseTextures)
	    g_pDirect3DDevice->SetTexture(0, g_pTexturePillar);
	else
	    g_pDirect3DDevice->SetTexture(0, NULL);
    g_pDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 
        0, g_iNumTriangles);

	// Render the second pillar.
	SetWorldTransformation(
		0.0f, 0.0f, 0.0f,                /* Rotations    */
		2.5f, 0.0f, g_fSignTranslation, /* Translations */
		1.0f, 5.0f, 1.0f);               /* Scaling      */
    g_pDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 
        0, g_iNumTriangles);

	// Render the sign board.
	SetWorldTransformation(
		0.0f, 3.14f, 0.0f,              /* Rotations    */
		0.0f, 0.0f, g_fSignTranslation, /* Translations */
		3.0, 3.0, 1.0);	                /* Scaling      */
    g_pDirect3DDevice->SetStreamSource(0, g_pTransparentSquareVertexBuf, 0, 
        sizeof(TRANSCUSTOMVERTEXSTRUCT));
	if (g_bUseTextures)
        g_pDirect3DDevice->SetTexture(0, g_pTextureWelcome);
	else
	    g_pDirect3DDevice->SetTexture(0, NULL);

	// Set the vertex format, and draw the sign board.
	g_pDirect3DDevice->SetFVF(D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX1);
    g_pDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
}

//////////////////////////////////////////////////////
// RenderCubeA()
//////////////////////////////////////////////////////
void RenderCubeA()
{
	double radians = timeGetTime() / 1000.0f;
    SetWorldTransformation(
		(float)radians, (float)radians, (float)radians, /* Rotations    */
		-4.0f, 1.0f, 14.0f,							    /* Translations */
		1.0f, 1.0f, 1.0f);							    /* Scaling      */
    g_pDirect3DDevice->SetStreamSource(0, g_pVertexBuf, 0, 
        sizeof(CUSTOMVERTEXSTRUCT));

	// See RenderSign() for an explanation of the texture stage settings.
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

	if (g_bUseTextures)
	    g_pDirect3DDevice->SetTexture(0, g_pTextureA);
	else
	    g_pDirect3DDevice->SetTexture(0, NULL);
	g_pDirect3DDevice->SetFVF(D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1);
    g_pDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 
        0, g_iNumTriangles);
}

//////////////////////////////////////////////////////
// RenderCubeB()
//////////////////////////////////////////////////////
void RenderCubeB()
{
    static float angle = 0.0f;
    angle += 0.01f;
    SetWorldTransformation(
		angle, 0.0f, 0.0f, /* Rotations    */
		0.5f, 0.0f, 14.0f, /* Translations */
		2.0f, 2.0f, 2.0f); /* Scaling      */
    g_pDirect3DDevice->SetStreamSource(0, g_pVertexBuf, 0, 
        sizeof(CUSTOMVERTEXSTRUCT));

	// See RenderSign() for an explanation of these texture stage settings.
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

	if (g_bUseTextures)
	    g_pDirect3DDevice->SetTexture(0, g_pTextureB);
	else
	    g_pDirect3DDevice->SetTexture(0, NULL);
    g_pDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 
        0, g_iNumTriangles);
}

//////////////////////////////////////////////////////
// RenderCubeC()
//////////////////////////////////////////////////////
void RenderCubeC()
{
    static float height = 0.0f;
	static int multiplier = 1;
	height += 0.02f * multiplier;
	if (height > 3.0f)
		multiplier = -1;
	else if (height < -1.0f)
		multiplier = 1;
	SetWorldTransformation(
		0.0f, 0.0f, 0.0f,     /* Rotations    */
		-1.5f, height, 13.0f, /* Translations */
		1.0f, 1.0f, 1.0f);	  /* Scaling      */
    g_pDirect3DDevice->SetStreamSource(0, g_pVertexBuf, 0, 
        sizeof(CUSTOMVERTEXSTRUCT));

	// See RenderSign() for an explanation of these texture stage settings.
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

	if (g_bUseTextures)
	    g_pDirect3DDevice->SetTexture(0, g_pTextureC);
	else
	    g_pDirect3DDevice->SetTexture(0, NULL);
    g_pDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 
        0, g_iNumTriangles);
}

//////////////////////////////////////////////////////
// RenderStarCube()
//////////////////////////////////////////////////////
void RenderStarCube()
{
	static float scale = 1.0f;
	scale += 0.02f;
	if (scale > 5.0f)
		scale = 1.0f;
	SetWorldTransformation(
		0.0f, 0.0f, 0.0f, /* Rotations    */
		-3.5f, 1.0, 7.0f, /* Translations */
		1.0, scale, 1.0); /* Scaling      */
    g_pDirect3DDevice->SetStreamSource(0, g_pVertexBuf, 0, 
        sizeof(CUSTOMVERTEXSTRUCT));

	// See RenderSign() for an explanation of these texture stage settings.
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

	if (g_bUseTextures)
	    g_pDirect3DDevice->SetTexture(0, g_pTextureStar);
	else
	    g_pDirect3DDevice->SetTexture(0, NULL);
    g_pDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 
        0, g_iNumTriangles);
}

//////////////////////////////////////////////////////
// RenderTransparentRectangles()
//////////////////////////////////////////////////////
void RenderTransparentRectangles()
{
	static float angle = 0.0f;
    angle += 0.01f;

	// Set the first color argument to the texture color.
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
	
	// Set the second color argument to be the output of the previous stage.
	// Because there is no previous stage, this argument results in
	// the same value as the D3DTA_DIFFUSE setting, which is the vertex
	// diffuse color or, lacking that, the default color of 0xFFFFFFFF.
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);

	// Set the color operation to multiply the colors (which is the default).
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);

	// Use the alpha value stored in the vertex's diffuse color.
	g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
	g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
    g_pDirect3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

	// Turn alpha blending on or off, based on the g_bAlphaBlendingOn variable.
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, g_bAlphaBlendingOn);

	// Turn on alpha testing.
	g_pDirect3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);

	SetWorldTransformation(
		angle, angle*2, 0.0f,  /* Rotations    */
		4.0f, 2.0f, 7.0f,      /* Translations */
		3.0, 3.0, 1.0);        /* Scaling      */
    g_pDirect3DDevice->SetStreamSource(0, g_pTransparentSquareVertexBuf, 0, 
        sizeof(TRANSCUSTOMVERTEXSTRUCT));
	if (g_bUseTextures)
        g_pDirect3DDevice->SetTexture(0, g_pTransparentSquareTexture);
	else
	    g_pDirect3DDevice->SetTexture(0, NULL);

	// Set vertex type, and draw the rectangle.
	g_pDirect3DDevice->SetFVF(D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX1);
    g_pDirect3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
}

//////////////////////////////////////////////////////
// InitVertices()
//////////////////////////////////////////////////////
HRESULT InitVertices()
{
    CUSTOMVERTEXSTRUCT cube[] =
    {
        // Front of cube.
        {-0.5f,  0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
        { 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f},
        {-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f},
        {-0.5f,  0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f},
        { 0.5f,  0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f},
        { 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f},

        // Right side of cube.
        {0.5f,  0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
        {0.5f, -0.5f,  0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f},
        {0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
        {0.5f,  0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
        {0.5f,  0.5f,  0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
        {0.5f, -0.5f,  0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f},

        // Back of cube.
        { 0.5f,  0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
        {-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f},
        { 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
        { 0.5f,  0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
        {-0.5f,  0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f},
        {-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f},

        // Left side of cube.
        {-0.5f,  0.5f,  0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
        {-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f},
        {-0.5f, -0.5f,  0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
        {-0.5f,  0.5f,  0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
        {-0.5f,  0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f},
        {-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f},

        // Top of cube.
        {-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f},
        {-0.5f, 0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f},
        { 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f},
        {-0.5f, 0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f},
        { 0.5f, 0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f},
        { 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f},

        // Bottom of cube.
        {-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f},
        { 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f},
        {-0.5f, -0.5f,  0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f},
        { 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f},
        { 0.5f, -0.5f,  0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f},
        {-0.5f, -0.5f,  0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f}
    };

	int i_numCoordsPerVertex = 24;

	// Create the vertex buffer.
	if(FAILED(g_pDirect3DDevice ->CreateVertexBuffer(sizeof(cube),
			0, D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1, D3DPOOL_DEFAULT, 
			&g_pVertexBuf, NULL)))
        return E_FAIL;

    CUSTOMVERTEXSTRUCT* pVertices;
    if(FAILED(g_pVertexBuf->Lock( 0, 0, (void**)&pVertices, 0)))
        return E_FAIL;
    memcpy(pVertices, cube, sizeof(cube));
    g_pVertexBuf->Unlock();

    g_iNumTriangles = (sizeof(cube) / sizeof(float)) / i_numCoordsPerVertex;

	TRANSCUSTOMVERTEXSTRUCT transparentSquare[] =
    {
        { 0.75f,  0.75f, 0.2f, 0.0f, 0.0f, 1.0f, 
            D3DCOLOR_ARGB(96,255,255,255), 0.0f, 0.0f},
        {-0.75f, -0.75f, 0.2f, 0.0f, 0.0f, 1.0f, 
            D3DCOLOR_ARGB(96,255,255,255), 1.0f, 1.0f},
        { 0.75f, -0.75f, 0.2f, 0.0f, 0.0f, 1.0f, 
            D3DCOLOR_ARGB(96,255,255,255), 0.0f, 1.0f},
        { 0.75f,  0.75f, 0.2f, 0.0f, 0.0f, 1.0f, 
            D3DCOLOR_ARGB(96,255,255,255), 0.0f, 0.0f},
        {-0.75f,  0.75f, 0.2f, 0.0f, 0.0f, 1.0f, 
            D3DCOLOR_ARGB(96,255,255,255), 1.0f, 0.0f},
        {-0.75f, -0.75f, 0.2f, 0.0f, 0.0f, 1.0f, 
            D3DCOLOR_ARGB(96,255,255,255), 1.0f, 1.0f}
    };

    if(FAILED(g_pDirect3DDevice ->CreateVertexBuffer(sizeof(transparentSquare),
            0, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1, 
            D3DPOOL_DEFAULT, &g_pTransparentSquareVertexBuf, NULL)))
        return E_FAIL;
    if(FAILED(g_pTransparentSquareVertexBuf->Lock(0, 0, (void**)&pVertices, 0)))
        return E_FAIL;
    memcpy(pVertices, transparentSquare, sizeof(transparentSquare));
    g_pTransparentSquareVertexBuf->Unlock();

    return S_OK;
}

//////////////////////////////////////////////////////
// SetWorldTransformation()
//////////////////////////////////////////////////////
VOID SetWorldTransformation(float fXRot, float fYRot, float fZRot, 
        float fXTrans, float fYTrans, float fZTrans,
        float fXScale, float fYScale, float fZScale)
{
    D3DXMATRIX worldMatrix;
    D3DXMATRIX tempMatrix;
    D3DXMatrixIdentity(&worldMatrix);
    D3DXMatrixScaling(&tempMatrix, fXScale, fYScale, fZScale);
    D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &tempMatrix);
    D3DXMatrixRotationX(&tempMatrix, fXRot);
    D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &tempMatrix);
    D3DXMatrixRotationY(&tempMatrix, fYRot);
    D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &tempMatrix);
    D3DXMatrixRotationZ(&tempMatrix, fZRot);
    D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &tempMatrix);
    D3DXMatrixTranslation(&tempMatrix, fXTrans, fYTrans, fZTrans);
    D3DXMatrixMultiply(&worldMatrix, &worldMatrix, &tempMatrix);
    g_pDirect3DDevice->SetTransform(D3DTS_WORLD, &worldMatrix);
}

//////////////////////////////////////////////////////
// SetViewTransformation()
//////////////////////////////////////////////////////
void SetViewTransformation()
{
    D3DXVECTOR3 vEyePt(0.0f, 0.0f, g_fZDistance);
    D3DXVECTOR3 vLookatPt(0.0f, 0.0f, g_fZLookAt);
    D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);
    D3DXMATRIXA16 matView;
    D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
    g_pDirect3DDevice->SetTransform(D3DTS_VIEW, &matView);
}

//////////////////////////////////////////////////////
// SetProjectionTransformation()
//////////////////////////////////////////////////////
void SetProjectionTransformation()
{
    D3DXMATRIXA16 matProj;
    D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f);
    g_pDirect3DDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}

//////////////////////////////////////////////////////
// InitLights()
//////////////////////////////////////////////////////
VOID InitLights()
{
    D3DLIGHT9 light0;
    ZeroMemory(&light0, sizeof(light0));

    light0.Type = D3DLIGHT_SPOT;
    light0.Ambient.r  = g_fAmbientLight;
    light0.Ambient.g  = g_fAmbientLight;
    light0.Ambient.b  = g_fAmbientLight;
    light0.Diffuse.r  = 1.0f;
    light0.Diffuse.g  = 1.0;
    light0.Diffuse.b  = 1.0;
    light0.Position.x = g_fLightPosition;
    light0.Position.y = g_fLightPosition;
    light0.Position.z = 0.0f;
    light0.Direction.x = -1.0f;
    light0.Direction.y = -1.0f;
    light0.Direction.z = 0.0f;
    light0.Attenuation0 = 1.0f;
    light0.Range = 50.0f;
    light0.Phi = 2.0f;
    light0.Theta = 1.0f;
    light0.Falloff = 1.0f;

    g_pDirect3DDevice->SetLight(0, &light0);
    g_pDirect3DDevice->LightEnable(0, g_bLightingOn);

	D3DMATERIAL9 material;
	ZeroMemory(&material, sizeof(material));
	material.Ambient.r = g_fMaterialRed;
	material.Ambient.g = g_fMaterialGreen;
	material.Ambient.b = g_fMaterialBlue;
	material.Ambient.a = 1.0f;
	material.Diffuse.r = 1.0;
	material.Diffuse.g = 1.0;
	material.Diffuse.b = 1.0;
	material.Diffuse.a = 1.0f;
	g_pDirect3DDevice->SetMaterial(&material);
}
