/**
 * @file
 * @brief SpriteMesh幚憰僋儔僗偺幚憰傪峴偆.
 * 
 * 
 * @author S.F.
 * @version $Id:
 *
 * Copyright (C) 2000-2002 Satoshi Fujiwara. All Rights Reserved.
 */
#pragma warning( disable : 4786 )	//STL偺寈崘奜偟

// 儊儌儕乕儕乕僋専弌梡
#include "sfdebug.h"

// SYSTEM INCLUDES
//

#include <stdio.h>
#include <queue>
#include "windows.h"
#include "windowsx.h"

#include "d3d8.h"
#include "d3dx8.h"
#include "dxerr8sf.h"


// PROJECT INCLUDES
//

#include "exception.h"
#include "sound.h"
#include "System.h"
#include "console.h"
#include "Obj.h"
#include "Obj3D.h"
#include "Obj3DL.h"
#include "AbstractSprite.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#include "SpriteMesh.h"


using namespace sf::system::console;
using namespace sf::system::console::sprite;


//////////////////////////////////////////////////////////////////////
// 峔抸/徚柵
//////////////////////////////////////////////////////////////////////

SpriteMesh::SpriteMesh(LPDIRECT3DDEVICE9 pD3DDevice)
{
	mNumMaterials = 0;
	mpMesh = NULL;
	mpMeshMaterials = NULL;
	mpMeshTextures = NULL;

	initialize(pD3DDevice);

}

SpriteMesh::~SpriteMesh()
{
	uninitialize();
}

// 弶婜壔 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void SpriteMesh::initialize(void)
{
	uninitialize();
	mbUse = false;

}// initialize()

// 弶婜壔 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void SpriteMesh::initialize(LPDIRECT3DDEVICE9	pD3DDevice)
{
	initialize();

	mpD3DDevice = pD3DDevice;
}// initialize()

// 僗僾儔僀僩梡僀儞僞乕僼僃乕僗偺儕儕乕僗 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void SpriteMesh::uninitialize(void)
{


    if( mpMeshMaterials != NULL ) 
        delete[] mpMeshMaterials;

    if( mpMeshTextures )
    {
        for( DWORD i = 0; i < mNumMaterials; i++ )
        {
            if( mpMeshTextures[i] )
                mpMeshTextures[i]->Release();
        }
        delete[] mpMeshTextures;
    }

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

	mbUse = false;
}// uninitialize

// 儊僢僔儏偺儘乕僪 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void SpriteMesh::load(const Info *pInfo,const D3DFORMAT textureFormat,const COLOR color)
{
	LPD3DXBUFFER pD3DXMtrlBuffer;
	HRESULT hr;

    // Load the mesh from the specified file
    if( FAILED( hr = D3DXLoadMeshFromX( (char *)(pInfo->fileName), D3DXMESH_SYSTEMMEM, 
                                   mpD3DDevice, NULL, 
                                   &pD3DXMtrlBuffer, &mNumMaterials, 
                                   &mpMesh ) ) )
    {
		std::string tmpErr("Sprite Load Error:");
		tmpErr += DXGetErrorString8(hr);
		throw FatalErrorException(tmpErr,__FILE__,__LINE__);
   }

    // We need to extract the material properties and texture names from the 
    // pD3DXMtrlBuffer

    D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
    mpMeshMaterials = new D3DMATERIAL8[mNumMaterials];
    mpMeshTextures  = new LPDIRECT3DTEXTURE8[mNumMaterials];

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

        // Set the ambient color for the material (D3DX does not do this)
        mpMeshMaterials[i].Ambient = mpMeshMaterials[i].Diffuse;
     
        // Create the texture
 //       if( FAILED( hr = D3DXCreateTextureFromFile( mpD3DDevice, 
  //                                             d3dxMaterials[i].pTextureFilename, 
   //                                            &mpMeshTextures[i] ) ) )
	 	HRESULT hr = D3DXCreateTextureFromFileExA(
			mpD3DDevice,
			d3dxMaterials[i].pTextureFilename,
			D3DX_DEFAULT,
			D3DX_DEFAULT,
			0,
			0,
			textureFormat,
			D3DPOOL_MANAGED,
			D3DX_FILTER_NONE,
			D3DX_FILTER_NONE,
			color,
			NULL,
			NULL,
			&mpMeshTextures[i]);
		if(FAILED(hr))
		{
    
			mpMeshTextures[i] = NULL;
        }
    }

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


// 僗僾儔僀僩偺昤夋(3D) -------------------------------------------------------
void SpriteMesh::draw(const Obj3DL * const pObj)
{

	HRESULT hr;
	if(!pObj->visibility())
		return;

	D3DMATRIX matrix_scaling=
	{
		pObj->scalingX(),0,0,0,
		0,pObj->scalingY(),0,0,
		0,0,pObj->scalingZ(),0,
		0,0,0,1
	};

	D3DMATRIX matrix_trans=
	{
		1,0,0,0,
		0,1,0,0,
		0,0,1,0,
		pObj->spaceX(),pObj->spaceY(),pObj->spaceZ(),1
	};
	

	D3DMATRIX matrix_rotx =
	{
		1,0,0,0,
		0,pObj->rotXCos(),pObj->rotXSin(),0,
		0,-pObj->rotXSin(),pObj->rotXCos(),0,
		0,0,0,1
	};

	D3DMATRIX matrix_roty=
	{
		pObj->rotYCos(),0,-pObj->rotYSin(),0,
		0,1,0,0,
		pObj->rotYSin(),0,pObj->rotYCos(),0,
		0,0,0,1
	};


	D3DMATRIX matrix_rotz =
	{
		pObj->rotZCos(),pObj->rotZSin(),0,0,
		-pObj->rotZSin(),pObj->rotZCos(),0,0,
		0,0,1,0,
		0,0,0,1
	};



	hr = mpD3DDevice->SetTransform(D3DTS_WORLD ,&matrix_trans);

	hr = mpD3DDevice->MultiplyTransform(D3DTS_WORLD ,&matrix_scaling);
	hr = mpD3DDevice->MultiplyTransform(D3DTS_WORLD ,&matrix_rotx);
	hr = mpD3DDevice->MultiplyTransform(D3DTS_WORLD ,&matrix_roty);
	hr = mpD3DDevice->MultiplyTransform(D3DTS_WORLD ,&matrix_rotz);

	setRenderState(pObj->drawMode());
	mpD3DDevice->SetRenderState(D3DRS_LIGHTING,		  TRUE);
	mpD3DDevice->SetRenderState(D3DRS_CULLMODE , 	  D3DCULL_CCW  );

	for( DWORD i = 0; i < mNumMaterials; i++ )
	{
		// Set the material and texture for this subset
		mpD3DDevice->SetMaterial( &mpMeshMaterials[i] );
		mpD3DDevice->SetTexture( 0, mpMeshTextures[i] );
    
		// Draw the mesh subset
		mpMesh->DrawSubset( i );
	}

}// draw()

