// ============================================================================
 // 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;

 }