// Mesh.cpp: implementation of the Mesh class.
//
//////////////////////////////////////////////////////////////////////

#include <D3dx8.h>
#include "Mesh.h"
extern IDirect3DDevice8*	g_pd3dDevice;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Mesh::Mesh()
{
	pMeshTextures	= NULL;
	pMeshMaterials	= NULL;
	pd3dxMesh		= NULL;
	dwNumMaterials	= 0L;
}

Mesh::~Mesh()
{
	cleanup();
}

void Mesh::cleanup()
{
    if( pMeshMaterials != NULL )
	{
        delete[] pMeshMaterials;
		pMeshMaterials = NULL;
	}

    if( pMeshTextures )
    {
        for( DWORD i = 0; i < dwNumMaterials; i++ )
        {
            if( pMeshTextures[i] )
                pMeshTextures[i]->Release();
        }
        delete[] pMeshTextures;
		pMeshTextures = NULL;
    }
    if( pd3dxMesh != NULL )
	{
        pd3dxMesh->Release();
		pd3dxMesh = NULL;
	}
}

HRESULT Mesh::CreateMesh(int NumFaces, int NumVertices)
{
	if(FAILED(D3DXCreateMeshFVF(NumFaces, NumVertices,
				 D3DXMESH_SYSTEMMEM,
				 D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE,
				 g_pd3dDevice, &pd3dxMesh)))
	{
		MessageBox(NULL, "Failed to create mesh", "", NULL);
        return E_FAIL;
    }
	return S_OK;
}

HRESULT Mesh::SetMaterials(DWORD NewNumMaterials, D3DMATERIAL8* NewMaterials)
{
	dwNumMaterials = NewNumMaterials;

    pMeshMaterials = new D3DMATERIAL8[dwNumMaterials];
	for(unsigned int i=0;i<dwNumMaterials;i++)
	{
		pMeshMaterials[i] = NewMaterials[i];
	}  

	return S_OK;
}

HRESULT Mesh::loadFromX(LPSTR pFilename)
{
    LPD3DXBUFFER pD3DXMtrlBuffer;

    // Load the mesh from the specified file
    if( FAILED( D3DXLoadMeshFromX( pFilename, D3DXMESH_SYSTEMMEM, 
                                   g_pd3dDevice, NULL, 
                                   &pD3DXMtrlBuffer, &dwNumMaterials, 
                                   &pd3dxMesh ) ) )
    {
		MessageBox(NULL, "Failed to load Mesh file", "", NULL);
        return E_FAIL;
    }

	// We need to extract the material properties and texture names from the 
    // pD3DXMtrlBuffer
    D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
    pMeshMaterials = new D3DMATERIAL8[dwNumMaterials];
    pMeshTextures  = new LPDIRECT3DTEXTURE8[dwNumMaterials];

    for( DWORD i=0; i<dwNumMaterials; i++ )
    {
        // Copy the material
        pMeshMaterials[i] = d3dxMaterials[i].MatD3D;

        // Set the ambient color for the material (D3DX does not do this)
        pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse;
     
        // Create the texture
        if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, 
                                               d3dxMaterials[i].pTextureFilename, 
                                               &pMeshTextures[i] ) ) )
        {
            pMeshTextures[i] = NULL;
        }
    }

    // Done with the material buffer
    pD3DXMtrlBuffer->Release();

    return S_OK;
}

void Mesh::draw()
{
    // Meshes are divided into subsets, one for each material. Render them in
    // a loop
    for( DWORD i=0; i<dwNumMaterials; i++ )
    {
        // Set the material and texture for this subset
		g_pd3dDevice->SetMaterial( &pMeshMaterials[i] );
		if(pMeshTextures!=NULL)
		{
			g_pd3dDevice->SetTexture( 0, pMeshTextures[i] );
		}
        
        // Draw the mesh subset
        pd3dxMesh->DrawSubset( i );
    }
}

LPD3DXMESH Mesh::GetD3DXMesh()
{
	return pd3dxMesh;
}

void Mesh::SetD3DXMesh(LPD3DXMESH NewMesh)
{
	pd3dxMesh = NewMesh;
}

