// ============================================================================
// Filename: MESH.cpp
// Description: Mesh Tutorial, Mesh class implementation. From the 32Bits
//				DirectX Techniques Series 1 Tutorial 4.
// Created by wizard version 0.1 Beta.
//
// Found a bug in this code framework? Need some help? Come to www.32bits.co.uk
// for support, feedback and the best DirectX dev community on the net!
// ============================================================================

#include <d3d8.h>
#include <d3dx8.h>
#include <dxerr8.h>

#include "CD3DMesh.h"

// =====================================================================================
// Constructor and destructor
// =====================================================================================

CD3DMesh::CD3DMesh()
{
	m_dwNumMaterials = 0;
	m_pMaterialsBuffer = NULL;
	m_pMaterials = NULL;
	m_pTextures = NULL;
	m_pMesh = NULL;

	// Remove these 2 if you are removing the inheritance from CD3DObject
	SetClassDesc("Basic Mesh");
	SetRTTI(MESH);
}


CD3DMesh::~CD3DMesh()
{
	Shutdown();
}

HRESULT CD3DMesh::Shutdown()
{
	// Free the materials array
	if(m_pMaterials)
		delete [] m_pMaterials;

	// If there are textures...
	if(m_pTextures)
	{
		// ...index through the texture array & release the texture object
		for(int iCount = 0; iCount < (int)m_dwNumMaterials; iCount++)
		{
			m_pTextures[iCount]->Release();
			m_pTextures[iCount] = NULL;
		}

		// Don't forget to delete the array as well
		delete [] m_pTextures;
	}

	// Release the mesh object
	if(m_pMesh)
		m_pMesh->Release();

	m_dwNumMaterials = 0;
	m_pMaterialsBuffer = NULL;
	m_pMaterials = NULL;
	m_pTextures = NULL;
	m_pMesh = NULL;

	return S_OK;
}

// =====================================================================================
// Initialisation
// =====================================================================================

HRESULT CD3DMesh::Initialise(char* szMeshFile, LPDIRECT3DDEVICE8& pDevice)
{
	HRESULT rslt = S_OK;

	// First, load the .X file into a mesh object, and fill out the materials buffer
	rslt = D3DXLoadMeshFromX(szMeshFile, D3DXMESH_MANAGED, pDevice, NULL,
							 &m_pMaterialsBuffer, &m_dwNumMaterials, &m_pMesh);
	if(FAILED(rslt)) { return Error(rslt, __LINE__, __FILE__, "Couldn't load mesh from .X file"); }
	

	// Next, get a pointer to the first element of data in the materials buffer, ready
	// to read out.
	D3DXMATERIAL* pMaterials = (D3DXMATERIAL*)m_pMaterialsBuffer->GetBufferPointer();

	// Create 2 arrays, 1 for textures and 1 for materials. D3DXLoadMeshFromX puts the
	// number of materials/textures (always the same) into m_dwNumMaterials above.
	m_pMaterials = new D3DMATERIAL8[m_dwNumMaterials];
	m_pTextures = new LPDIRECT3DTEXTURE8[m_dwNumMaterials];

	// Next, iterate through the pMaterials buffer.
	{
	for(int iCount = 0; iCount < (int)m_dwNumMaterials; iCount++)
	{
		// For each material buffer element, copy the D3DMATERIAL into this class' array.
		m_pMaterials[iCount] = pMaterials[iCount].MatD3D;

		// As we learnt in the Lighting tutorial (D3D Basics Series 3 Tut 4), each material
		// has diffuse & ambient light properties. Set the Ambient light ARGB to the diffuse
		// light ARGB.
		m_pMaterials[iCount].Ambient = m_pMaterials[iCount].Diffuse;		
		
		// Finally, create a texture from the file specified in the mateirals buffer and put
		// it in the m_pTextures array.
		rslt=D3DXCreateTextureFromFile(pDevice, pMaterials[iCount].pTextureFilename, &m_pTextures[iCount]);
		if(FAILED(rslt)) { return Error(rslt, __LINE__, __FILE__, "D3DXCreateTextureFromFile() failed."); }
	}
	}

	// m_pMaterialsBuffer is a COM object created by D3DXLoadMeshFromX. We only need it when
	// reading the data from the X file - now that we've populated our mesh, materials and
	// textures we can get rid of it.
	m_pMaterialsBuffer->Release();
	m_pMaterialsBuffer = NULL;

	return S_OK;
}

// =====================================================================================
// Rendering
// =====================================================================================

HRESULT CD3DMesh::Render(LPDIRECT3DDEVICE8& pDevice)
{
	HRESULT rslt = S_OK;

	// Rendering a mesh is very easy. Simply iterate through each material...
	{
	for(int iCount = 0; iCount < (int)m_dwNumMaterials; iCount++)
	{
		//... set the material and texture in the normal way
		rslt = pDevice->SetMaterial(&m_pMaterials[iCount]);
		if(FAILED(rslt)) { return Error(rslt, __LINE__, __FILE__, "Couldn't set the material."); }
		
		rslt = pDevice->SetTexture(0, m_pTextures[iCount]);
		if(FAILED(rslt)) { return Error(rslt, __LINE__, __FILE__, "Couldn't set the texture."); }
		
		//... then call ID3DXMesh::DrawSubset to draw the vertices in the mesh
		// that have this material and texture applied to them.
		rslt = m_pMesh->DrawSubset(iCount);
		if(FAILED(rslt)) { return Error(rslt, __LINE__, __FILE__, "DrawSubset() failed."); }
	}
	}

	return S_OK;

}