 #include "stdafx.h"
#include "Direct3D.h"

//bool CDirect3D::Fullscreen = true;
//int CDirect3D::Width = 1280;
//int CDirect3D::Height = 1024;

// If Fullscreen set to false, width and height are ignored
void CDirect3D::Init(HWND hWnd, bool Fullscreen, int Width, int Height)
{
   	this->Fullscreen = Fullscreen;
	this->Width = Width;
	this->Height = Height;
	this->hWnd = hWnd;
	// Create the D3D object.

	if( NULL == ( g_pD3D = Direct3DCreate9(  D3D_SDK_VERSION ) ) )
        return; 

    // Set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;
	Init3DParameters (d3dpp);

    // Create the D3DDevice, first try Hardware
    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
		                              D3DCREATE_HARDWARE_VERTEXPROCESSING,
                                      &d3dpp, &g_pd3dDevice ) ) )
    {

		if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
										  D3DCREATE_SOFTWARE_VERTEXPROCESSING,
										  &d3dpp, &g_pd3dDevice ) ) )
		{
			Initialized = false;
			return; 
		}

	}

    g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &m_DesktopMode );

	const D3DFORMAT fmtTextureArray[] = 
    {
        D3DFMT_A8R8G8B8,
        D3DFMT_A4R4G4B4,
        D3DFMT_A1R5G5B5,
    };
    const INT numTextureFmts = sizeof(fmtTextureArray) / sizeof(fmtTextureArray[0]);

    // Find a format that is supported as a texture map for the current mode
    for(int iFmt = 0; iFmt < numTextureFmts; iFmt++ )
    {
        if( SUCCEEDED( g_pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 
            m_DesktopMode.Format, 0, D3DRTYPE_TEXTURE, fmtTextureArray[iFmt] ) ) )
        {
            m_d3dfmtTexture = fmtTextureArray[iFmt];
            break;
        }
    }

	InitParameters();
	InitMatricies();
	InitLights();

	Initialized = true;
	ShowCursor(!Fullscreen);
}

CDirect3D::CDirect3D(HWND hWnd, bool Fullscreen, int Width, int Height)
{
 Init(hWnd, Fullscreen, Width, Height);   
}

CDirect3D::CDirect3D(HWND hWnd):
   g_pD3D(NULL),
   g_pd3dDevice(NULL),
   Initialized(false),
   Fullscreen(true),
   Width(1280),
   Height(1024)
{
  Init(hWnd, Fullscreen, Width, Height);   
}

CDirect3D::CDirect3D():
   g_pD3D(NULL),
   g_pd3dDevice(NULL),
   Initialized(false),
   Fullscreen(false),
   Width(800),
   Height(600)
 {

 };

CDirect3D::~CDirect3D()
{
    if( g_pd3dDevice != NULL ) 
        g_pd3dDevice->Release();

    if( g_pD3D != NULL )       
        g_pD3D->Release();

	ShowCursor(true);
}

void CDirect3D::InitParameters()
{
	g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE );
    g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE );
	g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
	g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);	
	g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_PHONG);
    g_pd3dDevice->SetRenderState(D3DRS_DITHERENABLE,   FALSE );
    g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE );

	//Texture Sampler
	g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

	//Enable Light
	g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
}

void CDirect3D::InitMatricies()
{
	D3DXVECTOR3 position(0.0f, 0.0f, -3.0f);
	D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
	D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
	D3DXMATRIX V;
	D3DXMatrixLookAtLH(&V, &position, &target, &up);
	g_pd3dDevice->SetTransform(D3DTS_VIEW, &V);
	
	D3DXMATRIX proj;
	D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI * 0.5f, (float)Height / (float)Width, 0.5f, 1000.0f);
	g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj);
}

void CDirect3D::InitLights()
{
	return;
	//TODO
    //Set the directional light (SUN)

	// Set up a material. The material here just has the diffuse and ambient
    // colors set to yellow. Note that only one material can be used at a time.
    D3DMATERIAL9 mtrl;
    ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );
    mtrl.Diffuse.r = mtrl.Ambient.r = 0.0f;
    mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
    mtrl.Diffuse.b = mtrl.Ambient.b = 1.0f;
    mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
    g_pd3dDevice->SetMaterial( &mtrl );

    // Set up a white, directional light, with an oscillating direction.
    // Note that many lights may be active at a time (but each one slows down
    // the rendering of our scene). However, here we are just using one. Also,
    // we need to set the D3DRS_LIGHTING renderstate to enable lighting
    D3DXVECTOR3 vecDir;
    D3DLIGHT9 light;
    ZeroMemory( &light, sizeof(D3DLIGHT9) );
    light.Type = D3DLIGHT_SPOT;
	
	light.Position = D3DXVECTOR3( 0.0f, 0.0f, -3.0f );
    light.Direction = D3DXVECTOR3( 0.0f, 0.0f, 1.0f);
    light.Theta        = 0.5f;
    light.Phi          = 1.0f;
    light.Falloff      = 1.0f;
    light.Attenuation0 = 0.0f;
    light.Attenuation1 = 0.0f;
    light.Attenuation2 = 1.0f;

    light.Diffuse.r  = 1.0f;
    light.Diffuse.g  = 1.0f;
    light.Diffuse.b  = 1.0f;

	light.Range       = 10.0f;
    g_pd3dDevice->SetLight( 0, &light );
    g_pd3dDevice->LightEnable( 0, TRUE );
 
	g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
    g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00202020 );
}

void CDirect3D::Init3DParameters(D3DPRESENT_PARAMETERS &d3dpp)
{
    D3DDISPLAYMODE d3ddm;
	g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm );

    ZeroMemory( &d3dpp, sizeof(d3dpp) );
	
	d3dpp.Windowed = TRUE;	
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = d3ddm.Format;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

	d3dpp.hDeviceWindow = this->hWnd;

	if (Fullscreen)
	{
		d3dpp.Windowed = FALSE;	
		d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
		d3dpp.BackBufferWidth = Width;
		d3dpp.BackBufferHeight = Height;
		d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; //pixel format
		d3dpp.BackBufferCount = 1;
		d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
		d3dpp.MultiSampleQuality = 0;
	}
}

//--------------------------------------------
//Public Methods
//--------------------------------------------
void CDirect3D::Clear()
{
  if (Initialized)
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
}

void CDirect3D::SwapBuffers()
{
  if (Initialized)
	g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

D3DFORMAT CDirect3D::GetTextureFormat()
{
	return this->m_d3dfmtTexture;
}
