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

#include <D3dx9.h>
#include "Mesh.h"
extern IDirect3DDevice9*	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;
	}
	dwNumMaterials	= 0L;
}

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, D3DMATERIAL9* NewMaterials)
{
	dwNumMaterials = NewNumMaterials;

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

	return S_OK;
}

//Sets the textures for this mesh to those specified in the array
HRESULT Mesh::SetTextures(DWORD NewNumTextures, LPDIRECT3DTEXTURE9* NewTextures)
{
    

    pMeshTextures = new LPDIRECT3DTEXTURE9[NewNumTextures];
	for(unsigned int i=0;i<NewNumTextures;i++)
	{
		pMeshTextures[i] = NewTextures[i];
	}  

	return S_OK;
}

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

    // Load the mesh from the specified file
    if( FAILED( D3DXLoadMeshFromX( "tiger.x", D3DXMESH_SYSTEMMEM, 
                g_pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL,
			    &dwNumMaterials, &pd3dxMesh ) ) )
    {	
        // If model is not in current folder, try parent folder
        if( FAILED( D3DXLoadMeshFromX( "..\\tiger.x", D3DXMESH_SYSTEMMEM, 
                g_pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL, 
                &dwNumMaterials, &pd3dxMesh ) ) )
        {
            MessageBox(NULL, "Could not find tiger.x",
			        "Herds", MB_OK);
            return E_FAIL;
        }
    }

    // We need to extract the material properties and texture names from the 
    // pD3DXMtrlBuffer
    D3DXMATERIAL*       d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
    pMeshMaterials = new D3DMATERIAL9[dwNumMaterials];
    pMeshTextures  = new LPDIRECT3DTEXTURE9[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;

        pMeshTextures[i] = NULL;
        if( d3dxMaterials[i].pTextureFilename != NULL && 
            lstrlen(d3dxMaterials[i].pTextureFilename) > 0 )
        {
            // Create the texture
            if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, 
                                                 d3dxMaterials[i].pTextureFilename, 
                                                &pMeshTextures[i] ) ) )
            {
                // If texture is not in current folder, try parent folder
                const TCHAR* strPrefix = TEXT("..\\");
                const int lenPrefix = lstrlen( strPrefix );
                TCHAR strTexture[MAX_PATH];
                lstrcpyn( strTexture, strPrefix, MAX_PATH );
                lstrcpyn( strTexture + lenPrefix, d3dxMaterials[i].pTextureFilename, MAX_PATH - lenPrefix );
                // If texture is not in current folder, try parent folder
                if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, 
                                                    strTexture, 
                                                    &pMeshTextures[i] ) ) )
                {
                    MessageBox(NULL, "Could not find texture map", "Herds", MB_OK);
                }
            }
        }
    }

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


 //   LPD3DXBUFFER pD3DXMtrlBuffer;
	////LPD3DXBUFFER pEffectInstances;

 //   // Load the mesh from the specified file
 //   if( FAILED( D3DXLoadMeshFromX( pFilename, D3DXMESH_SYSTEMMEM, 
 //                                  g_pd3dDevice, NULL, 
 //                                  &pD3DXMtrlBuffer, NULL, &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 D3DMATERIAL9[dwNumMaterials];
 //   pMeshTextures  = new LPDIRECT3DTEXTURE9[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;
 //    
 //       pMeshTextures[i] = NULL;
 //       if( d3dxMaterials[i].pTextureFilename != NULL && 
 //           lstrlen(d3dxMaterials[i].pTextureFilename) > 0 )
 //       {
 //           // Create the texture
 //           if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, 
 //                                               d3dxMaterials[i].pTextureFilename, 
 //                                               &pMeshTextures[i] ) ) )
 //           {
 //               pMeshTextures[i] = NULL;
 //               //MessageBox(NULL, "Could not find texture map", "Herds", MB_OK);
 //           }
 //       }
 //   }

 //   // 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] );
		}
        else
            g_pd3dDevice->SetTexture( 0, NULL);
        
        // Draw the mesh subset
        pd3dxMesh->DrawSubset( i );
    }
}

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

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

void Mesh::DeleteD3DXMesh()
{
	if(pd3dxMesh!=NULL)
	{
		pd3dxMesh->Release();
		pd3dxMesh = NULL;
	}
}
