/**
 * @file
 * @brief Sprite3D幚憰僋儔僗偺幚憰傪峴偆.
 * 
 * 
 * @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"
#include "ConsoleImpl.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#include "Sprite3D.h"

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

//////////////////////////////////////////////////////////////////////
// 峔抸/徚柵
//////////////////////////////////////////////////////////////////////
// 僐儞僗僩儔僋僞 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
Sprite3D::Sprite3D(LPDIRECT3DDEVICE9 pD3DDevice)
{
	mpSprite3DVtBuf = NULL;
	mpSpriteTexture = NULL;
	mCellWidth = mCellHeight = 0.0f;
	mCellCount = 0.0f;

	initialize(pD3DDevice);
}

// 僨僗僩儔僋僞 亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
Sprite3D::~Sprite3D()
{
	uninitialize();
}//Sprite3D

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

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

	mpD3DDevice = pD3DDevice;
}// initialize()

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

	if(mpSprite3DVtBuf)
	{
		mpSprite3DVtBuf->Release();
		mpSprite3DVtBuf = NULL;
	}

	if(mpSpriteTexture){
		mpSpriteTexture->Release();
		mpSpriteTexture = NULL;
	}
/*
    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()


// 3D僗僾儔僀僩偺儘乕僪 -亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅亅
void Sprite3D::load(const sprite::Info *pInfo,const D3DFORMAT textureFormat,const COLOR color)
{
	// 僥僋僗僠儍偺儘乕僪 
	D3DXIMAGE_INFO img_info;
	HRESULT hr = D3DXCreateTextureFromFileExA(
		mpD3DDevice,
		pInfo->fileName,
		D3DX_DEFAULT,
		D3DX_DEFAULT,
		0,
		0,
		textureFormat,
		D3DPOOL_MANAGED,
		D3DX_FILTER_NONE,
		D3DX_FILTER_NONE,
		color,
		&img_info,
		NULL,
		&mpSpriteTexture);
	
	if(FAILED(hr))
	{
		std::string tmpErr("Sprite Load Error:");
		tmpErr += DXGetErrorString8(hr);
		throw FatalErrorException(tmpErr,__FILE__,__LINE__);
	}

	DWORD twidth = img_info.Width;
	DWORD theight = img_info.Height;


	mWidth = twidth;
	mHeight = theight;
	
	if(pInfo->cellWidth){
		twidth = mCellWidth = pInfo->cellWidth;
	}

	if(pInfo->cellHeight){
		theight = mCellHeight = pInfo->cellHeight;
	}
	

	//僀儊乕僕僒僀僘偺庢摼
	
	float width  = (float)twidth / screen::HEIGHT;
	float height = (float)theight / screen::HEIGHT;

	float center_x = pInfo->centerX / (float)screen::HEIGHT;
	float center_y = pInfo->centerY / (float)screen::HEIGHT;

	mCenterX = pInfo->centerX;
	mCenterY = pInfo->centerY;

	float start_x = center_x - width;
	float start_y = center_y - height;

	float end_x = center_x + width;
	float end_y = center_y + height;

	D3DSURFACE_DESC d3dsd;

	mpSpriteTexture->GetLevelDesc(0,&d3dsd);
	
	float cell_width = (float)twidth / (float)d3dsd.Width;
	float cell_height = (float)theight / (float)d3dsd.Height;

	int count_x = 1;
	int count_y = 1;

	if(mCellWidth && mCellHeight)
	{
		count_x = mWidth / mCellWidth;
		count_y = mHeight / mCellHeight;
		mCellCount = count_x * count_y;
	}
	else
	{
		mCellCount = 1;
	}

	int vert_size = sizeof(Vertex2) * 4 * mCellCount;

	hr = mpD3DDevice->CreateVertexBuffer( vert_size,
			0, Vertex2FVF,D3DPOOL_MANAGED , &mpSprite3DVtBuf );		

	if(FAILED(hr)){
		std::string tmpErr("Sprite Load Error:");
		tmpErr += DXGetErrorString8(hr);
		throw FatalErrorException(tmpErr,__FILE__,__LINE__);
	}

	LPBYTE pvertices;

	mpSprite3DVtBuf->Lock( 0, vert_size, (BYTE**)&pvertices, 0 );
	
	int i,j;
	for(j = 0;j < count_y;j++)
	{
		for(i = 0;i < count_x;i++)
		{
			Vertex2 vert_image[] =
			{
				{ start_x,start_y, 0.0f, 0xffffffff,0x0000000,cell_width*i,    cell_height*(j+1)},
				{ start_x,end_y,   0.0f, 0xffffffff,0x0000000,cell_width*i,    cell_height*(j)},
				{ end_x,  start_y, 0.0f, 0xffffffff,0x0000000,cell_width*(i+1),cell_height*(j+1)},
				{ end_x,  end_y,   0.0f, 0xffffffff,0x0000000,cell_width*(i+1),cell_height*(j)}
			};
			memcpy( pvertices, vert_image, sizeof(vert_image) );
			pvertices += sizeof(Vertex2) * 4;
		}
	}
	
	mpSprite3DVtBuf->Unlock();

	use(true);

}//load()

// 僗僾儔僀僩偺昤夋(3D) -------------------------------------------------------
void Sprite3D::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);


	Vertex2 *ptlv;
	mpSprite3DVtBuf->Lock(0,0,(BYTE **)&ptlv,0);

	ptlv[0].specular = 
		ptlv[1].specular = 
		ptlv[2].specular = 
		ptlv[3].specular = pObj->specular();
	
	ptlv[0].diffuse =
		ptlv[1].diffuse = 
		ptlv[2].diffuse =
		ptlv[3].diffuse = pObj->color();
	
	mpSprite3DVtBuf->Unlock();

	hr = mpD3DDevice->SetTexture(0,mpSpriteTexture);
	setRenderState(pObj->drawMode());
	mpD3DDevice->SetRenderState(D3DRS_LIGHTING,		  FALSE);
	mpD3DDevice->SetRenderState(D3DRS_CULLMODE , 	  D3DCULL_NONE  );

	hr = mpD3DDevice->SetStreamSource(0,mpSprite3DVtBuf,sizeof(Vertex2));
	hr = mpD3DDevice->SetVertexShader(Vertex2FVF);

	hr = mpD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,pObj->index(),2);

	mpD3DDevice->SetTexture(0,NULL);

}// draw()

