/**
 * @file
 * @brief 画面描画（スプライト・背景画像）の実装を行う.
 *
 * @author S.F.
 * @version $Id:
 *
 * Copyright (C) 2000-2002 Satoshi Fujiwara. All Rights Reserved.
 */


#pragma warning( disable : 4786 4251)	//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 "Obj2D.h"
#include "ObjRectangle.h"
#include "ObjQuadrangle.h"
#include "Obj3D.h"
#include "Obj3DL.h"
#include "input.h"
#include "AbstractSprite.h"



#include "ConsoleImpl.h"
#include "Main.h"
#include "Sprite2D.h"
#include "Sprite3D.h"
#include "SpriteMesh.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

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


ConsoleImpl::ConsoleImpl()
{
	mbD3DReady = false;
	mpD3D = NULL;
	mpD3DDevice = NULL;
	mpD3DXSprite = NULL;
}

ConsoleImpl::ConsoleImpl(const HWND hwnd,const bool bWindow)
{
	// HWNDのコピー
	mhWndMain = hwnd;
	mbWindowed = bWindow;

}

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

void ConsoleImpl::initialize(void)
{
	initialize(mhWndMain,mbWindowed);
};
// 初期化 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void ConsoleImpl::initialize(const HWND hwnd,const bool bWindow)
{
	int i;
	HRESULT hr;
				
	// 各項目のクリア
				
	mpD3D = NULL;
	mpD3DDevice = NULL;
	mpD3DXSprite = NULL;
	
	mbD3DReady = false;
	mbWindowed = false;
	
	for(i = 0;i < font::COUNT_MAX;i++)
	{
		mpFontTexture[i] = NULL;
	}
	
	ZeroMemory( &mD3Dpp, sizeof(mD3Dpp) );
	
	// HWNDのコピー
	mhWndMain = hwnd;
	
	// D3D Object の生成
	if( NULL == ( mpD3D = Direct3DCreate8( D3D_SDK_VERSION ) ) )
		throw FatalErrorException("D3D8 Create Error",__FILE__,__LINE__);
	
	checkAndSetDevice();
	
	//
	//D3DPRESENT_PARAMETERS mD3Dpp; 
	
	ZeroMemory(&mD3Dpp,sizeof(mD3Dpp));

	if(bWindow){
		//ウィンドウモード（デバッグ用）
		D3DDISPLAYMODE d3ddm;
		if( FAILED( hr = mpD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
		{	throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);	}
		mD3Dpp.Windowed = TRUE;
		mD3Dpp.BackBufferFormat = d3ddm.Format;
		mD3DFormat = d3ddm.Format;
		mD3Dpp.SwapEffect = D3DSWAPEFFECT_COPY;
		mbWindowed = true;
	} else {
		//フルスクリーンモード
		mD3Dpp.Windowed = FALSE;
		mD3Dpp.BackBufferWidth = screen::WIDTH;
		mD3Dpp.BackBufferHeight = screen::HEIGHT;
		mD3Dpp.BackBufferCount = 1;
		mD3Dpp.BackBufferFormat = mD3DFormat;
		mD3Dpp.FullScreen_RefreshRateInHz = 0;
		mD3Dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE ;
		mD3Dpp.SwapEffect = D3DSWAPEFFECT_COPY;
//		mD3Dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
		mbWindowed = false;
	}
	
	mD3Dpp.EnableAutoDepthStencil = TRUE;
	mD3Dpp.AutoDepthStencilFormat = mDepthFormat;
	//	mD3Dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
	mD3Dpp.hDeviceWindow = hwnd;
	
	//3Dデバイスの取得//
	// HALかREFのどちらかを取得 //
	if( FAILED( hr = mpD3D->CreateDevice( D3DADAPTER_DEFAULT, mD3DDeviceType, hwnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&mD3Dpp, &mpD3DDevice ) ) )
	{
		throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
	}

	// スプライトオブジェクトの初期化
	for(i = 0;i < sprite::MAX;i++)
	{
		mpSprite[i] = NULL;
		//mSprite[i]->initialize(mpD3DDevice);
	}

	
	// D3DDeviceがReset時に破棄しなくてはいけないオブジェクトの初期化
	initNotManagedObjects();
	
	// 画面・ビューポートのコーディネート
	initConsoleViewStyle();
	
	// デバイスの初期化
	initDeviceStates();
	
	// 文字フォントのロード
	loadFont();

	// Lock the surface and write the alpha values for the set pixels
#ifdef _DEBUG 
	D3DSURFACE_DESC des;
	mpFontTexture[0]->GetLevelDesc(0,&des);
	char pdebug_str[256];
	sprintf(pdebug_str,"format: %d ",des.Format);
	OutputDebugString(pdebug_str);
#endif
	//クリップ領域をクリア//
	mbD3DReady = true;
}//initialize()

// 最適な３Ｄデバイスを得る --------------------------------------------------
void ConsoleImpl::checkAndSetDevice(const D3DDEVTYPE devtype)
{
	try {
		checkAndSetDeviceType(devtype);
	} catch(RecoverbleErrorException e) {
		if(e.errorType() == sf::system::Exception::DEVICE_NOT_FOUND){
			try {
				checkAndSetDeviceType(D3DDEVTYPE_REF);
			} catch (RecoverbleErrorException e){
				if(e.errorType() == sf::system::Exception::DEVICE_NOT_FOUND){
					throw FatalErrorException("Device Not Found",__FILE__,__LINE__,sf::system::Exception::DEVICE_NOT_FOUND);
				}
			} catch(...) {
				throw;
			}
		} else {
			throw;
		}
	} catch(...){
		throw;
	}
}// checkAndSetDevice()

// デバイスタイプをテストする -------------------------------------------------
void ConsoleImpl::checkAndSetDeviceType(const D3DDEVTYPE devtype)
{
	// アルファブレンドスプライトをサポートしているもっとも高速なタイプ検出
	// といってもHALかREFかを選ぶだけですが...
	// REFでもダメならエラーで終了 
	
	HRESULT hr = S_OK;
	D3DCAPS8	d3dcaps8;
	ZeroMemory(&d3dcaps8,sizeof(d3dcaps8));
	
	hr = mpD3D->GetDeviceCaps(D3DADAPTER_DEFAULT,devtype,&d3dcaps8);
	if(SUCCEEDED(hr))
	{	
		if(!((d3dcaps8.SrcBlendCaps & D3DPBLENDCAPS_SRCALPHA) &&
			(d3dcaps8.DestBlendCaps & D3DPBLENDCAPS_INVSRCALPHA) &&
			(d3dcaps8.TextureFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR ) &&
			(d3dcaps8.TextureOpCaps & D3DTEXOPCAPS_MODULATE )
			)){
			throw RecoverbleErrorException("Device Not Found",__FILE__,__LINE__,sf::system::Exception::DEVICE_NOT_FOUND);
		} else {
			mD3DDeviceType = devtype;
			
			// 16bitのバックバッファのフォーマットを得る
			checkAndSetBackBufferFormat();
			
			checkAndSetDepthFormat();
			
			// 透過処理が使用できるテクスチャフォーマットを得る
			checkAndSetTextureFormat();
		}
		
	}  
	return;
}// checkAndSetDeviceType()
			
// バックバッファのフォーマットを得る ---------------------------------------
void ConsoleImpl::checkAndSetBackBufferFormat(void)
{
	//最適な、16bitカラーモードの選択
	if(SUCCEEDED(mpD3D->CheckDeviceType(D3DADAPTER_DEFAULT,mD3DDeviceType ,D3DFMT_A1R5G5B5,D3DFMT_A1R5G5B5,FALSE)))
		mD3DFormat = D3DFMT_A1R5G5B5;
	else
	{
		if(SUCCEEDED(mpD3D->CheckDeviceType(D3DADAPTER_DEFAULT,mD3DDeviceType ,D3DFMT_A4R4G4B4,D3DFMT_A4R4G4B4,FALSE))){
			mD3DFormat = D3DFMT_A4R4G4B4;
		} else {
			if(SUCCEEDED(mpD3D->CheckDeviceType(D3DADAPTER_DEFAULT,mD3DDeviceType ,D3DFMT_X1R5G5B5,D3DFMT_X1R5G5B5,FALSE))){
				mD3DFormat = D3DFMT_X1R5G5B5;
			} else {
				if(SUCCEEDED(mpD3D->CheckDeviceType(D3DADAPTER_DEFAULT,mD3DDeviceType ,D3DFMT_R5G6B5,D3DFMT_R5G6B5,FALSE))){
					mD3DFormat = D3DFMT_R5G6B5;
				} else {
					if(SUCCEEDED(mpD3D->CheckDeviceType(D3DADAPTER_DEFAULT,mD3DDeviceType ,D3DFMT_X4R4G4B4,D3DFMT_X4R4G4B4,FALSE))){
						mD3DFormat = D3DFMT_X4R4G4B4;
					} else {
						throw RecoverbleErrorException("Back Buffer Format Not Found",__FILE__,__LINE__,sf::system::Exception::DEVICE_NOT_FOUND);
					}
				}
			}
		}
	}
}// checkAndSetBackBufferFormat()
			
// テクスチャサーフェースのフォーマットを取得する -----------------------------
void ConsoleImpl::checkAndSetTextureFormat(void)
{
	// αビットをもつテクスチャーフォーマットを探す 
	if(SUCCEEDED(mpD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT,mD3DDeviceType,mD3DFormat,0,D3DRTYPE_TEXTURE,D3DFMT_A1R5G5B5))){
		mTextureFormat = D3DFMT_A1R5G5B5;
	} else {
		if(SUCCEEDED(mpD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT,mD3DDeviceType,mD3DFormat,0,D3DRTYPE_TEXTURE,D3DFMT_A4R4G4B4))){
			mTextureFormat = D3DFMT_A4R4G4B4;
		} else {
			if(SUCCEEDED(mpD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT,mD3DDeviceType,mD3DFormat,0,D3DRTYPE_TEXTURE,D3DFMT_A8R3G3B2))){
				mTextureFormat = D3DFMT_A8R3G3B2;
			} else {
				throw RecoverbleErrorException("Texture Format Not Found",__FILE__,__LINE__,sf::system::Exception::DEVICE_NOT_FOUND);
			}
		}
	}
}// checkAndSerTextureFormat()

// 深度バッファのフォーマットを得る ------------------------------------------
void ConsoleImpl::checkAndSetDepthFormat()
{
	if(SUCCEEDED(mpD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT,mD3DDeviceType,mD3DFormat,D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,D3DFMT_D16))){
		mDepthFormat = D3DFMT_D16;
	} else {
		if(SUCCEEDED(mpD3D->CheckDeviceFormat(D3DADAPTER_DEFAULT,mD3DDeviceType,mD3DFormat,D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,D3DFMT_D16_LOCKABLE))){
			mDepthFormat = D3DFMT_D16_LOCKABLE;
		} else {
			throw RecoverbleErrorException("Depth Format Not Found",__FILE__,__LINE__,sf::system::Exception::DEVICE_NOT_FOUND);
		}
	}
}// checkAndSetDepthFormat()

// レンダリングステート、テクスチャステージステートの初期化 --------------------
void ConsoleImpl::initDeviceStates(void)
{
	HRESULT hr;
	
	hr = mpD3DDevice->SetRenderState(D3DRS_SPECULARENABLE,    TRUE);
	if (FAILED(hr)){
		throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
	}
	
	//D3Dデバイスのレンダリングステートの設定//////////////////////
	
	//ライティング
	hr = mpD3DDevice->SetRenderState(D3DRS_LIGHTING,		  TRUE);
	if (FAILED(hr)){
		throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
	}

	//Zバッファ
	hr = mpD3DDevice->SetRenderState(D3DRS_ZENABLE, 		  TRUE);
	if (FAILED(hr)){
		throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
	}
//	hr = mpD3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, 		  TRUE);
	
	// Enable vertices to have colors 

	hr = mpD3DDevice->SetRenderState(D3DRS_COLORVERTEX, 	  TRUE);
	if (FAILED(hr)){
		throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
	}
	
	// Enable vertices to have colors 
/*	hr = mpD3DDevice->SetRenderState(D3DRS_CULLMODE , 	  D3DCULL_NONE  );
	if (FAILED(hr)){
		system::instance()->errorTerminate(DXGetErrorString8(hr));
		return false;
	}
*/
	// クリッピング
	hr = mpD3DDevice->SetRenderState( D3DRS_CLIPPING,        TRUE);
	if (FAILED(hr)){
		throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
	}
	
/*	hr = mpD3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE,	  TRUE);
	if (FAILED(hr)){
		system::instance()->errorTerminate(DXGetErrorString8(hr));
		return false;
	}
*/
	hr = mpD3DDevice->SetRenderState(D3DRS_AMBIENT,	  0xFF808080);
	if (FAILED(hr)){
		throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
	}


	//			hr = mpD3DDevice->SetRenderState(D3DRS_COLORKEYENABLE,		 TRUE);
	//			if (FAILED(hr))
	//				return false;			
	
	//	hr = mpD3DDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
	//	if (FAILED(hr))
	//		return hr;
	
	
	//	hr = mpD3DDevice->SetRenderState(	D3DRS_ALPHATESTENABLE	, TRUE);
	//	if (FAILED(hr))
	//		return hr;
	
	//	hr = mpD3DDevice->SetRenderState( D3DRS_ALPHAREF, 0xff);
	//	if (FAILED(hr))
	//		return hr;
	
	
	// hr = mpD3DDevice->SetRenderState(D3DRS_DITHERENABLE,	   TRUE);
	//			hr = mpD3DDevice->SetRenderState(D3DRS_ANTIALIAS,	   D3DANTIALIAS_NONE );
	//			if (FAILED(hr))
	//				return false;			
	
//	hr = mpD3DDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);
//	if (FAILED(hr)){
//		system::instance()->errorTerminate(DXGetErrorString8(hr));
//		return false;
//	}
	
	hr = mpD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,	TRUE);	
	if (FAILED(hr)){
		throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
	}
	
	hr = mpD3DDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
	if (FAILED(hr)){
		throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
	}
	
	hr = mpD3DDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
	if (FAILED(hr)){
		throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
	}
	
	// テクスチャステージステートの設定 //
	mpD3DDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
	
	mpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
	mpD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
	mpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
	mpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
	mpD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
	
	mpD3DDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_POINT );
	mpD3DDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT );

	mpD3DDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE );

/*	mpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
	mpD3DDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
*/

}// initDeviceStates()

// 画面の初期化ビューポートの設定など ------------------------------------------
void ConsoleImpl::initConsoleViewStyle(void)
{

	HRESULT hr = E_FAIL;

	initLight();	

	mpD3DDevice->BeginScene();

	initMatrix();


	
	//画面クリア//

	
	mpD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_COLORVALUE(0.0f,0.5f,0.0f,0.0f),0.0f,0);
	
	mpD3DDevice->EndScene();
	
	mpD3DDevice->Present(NULL,NULL,NULL,NULL);
	
	//ビューポートの設定//
	
	D3DVIEWPORT8 d3dv;
	
	d3dv.X = viewport::X;
	d3dv.Y = viewport::Y;
	d3dv.Width = viewport::WIDTH;
	d3dv.Height = viewport::HEIGHT;
	d3dv.MinZ = viewport::Z_MIN;
	d3dv.MaxZ = viewport::Z_MAX;
	
	hr = mpD3DDevice->SetViewport(&d3dv);
	if(FAILED(hr)){
		throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
	}
	
	//　ビューポート内のクリア
	mpD3DDevice->BeginScene();
	clearScreen();
	mpD3DDevice->EndScene();
	mpD3DDevice->Present(NULL,NULL,NULL,NULL);
}//initConsoleViewStyle();

// ライトの初期化 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void ConsoleImpl::initLight()
{
	D3DLIGHT8 light;
	ZeroMemory(&light, sizeof(D3DLIGHT8));
	light.Type = D3DLIGHT_DIRECTIONAL;
	light.Diffuse.r = 1.0f;
	light.Diffuse.g = 1.0f;
	light.Diffuse.b = 1.0f;
	D3DXVECTOR3 v(0.7f, -0.8f, 0.1f);
	D3DXVec3Normalize((D3DXVECTOR3 *)&light.Direction, &v);
	light.Range = 100.0f;
	
	mpD3DDevice->SetLight(0, &light);
	mpD3DDevice->LightEnable(0, TRUE);
	mpD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
}

// 行列の初期化 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
void ConsoleImpl::initMatrix()
{
		// 3D View の設定(参考：ぷよーんさんのライブラリ) 
	// ほとんど、そのままです。

	//基本値設定
	float aspect = (float) screen::WIDTH / screen::HEIGHT;	    //アスペクト比(高さを1としたときの幅)
	float aspect_v = (float) viewport::WIDTH / viewport::HEIGHT;	    //アスペクト比(高さを1としたときの幅)

	float depth = 1.5f;										//奥行きZ
	float fovy  = (float)atan(1.0f / depth) * 2.0f;					//視野をZ=0でデバイスの幅と高さに合わせる
	
	//座標を揃える
	D3DXMATRIX mat_view;
	D3DXMatrixLookAtLH( &mat_view, 
		&D3DXVECTOR3( aspect, -1.0f,-depth),
		&D3DXVECTOR3( aspect, -1.0f, 0.0f),
		&D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );

/*	D3DXMatrixLookAtLH( &mat_view, &D3DXVECTOR3( 0.0f, 3.0f,-5.0f ),
                              &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
                              &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );
*/
	mpD3DDevice->SetTransform( D3DTS_VIEW, &mat_view );

	//奥行きに対する比率を調整
	D3DXMATRIX mat_proj;
//	D3DXMatrixPerspectiveFovLH( &mat_proj, D3DX_PI/4, aspect_v, 1.0f, 100.0f );

	D3DXMatrixPerspectiveFovLH( &mat_proj,fovy, aspect_v, 1.0f, 100.0f );

	mpD3DDevice->SetTransform( D3DTS_PROJECTION, &mat_proj );
	
	// 

}//initMatrix()

// create時およびreset時の再初期化---------------------------------------------
void ConsoleImpl::initNotManagedObjects(void)
{
	HRESULT hr;

	//スプライトオブジェクト
	
	if(FAILED(hr = D3DXCreateSprite(mpD3DDevice,&mpD3DXSprite)))
	{
		throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
	}

}// initNotManagedObjects

void ConsoleImpl::releaseNotManagedObjects(void)
{
	
	if(mpD3DXSprite)
	{
		mpD3DXSprite->Release();
		mpD3DXSprite = NULL;
	}
	
}// releaseNotManagedObjects

// 終了処理 -------------------------------------------------------------------
void ConsoleImpl::uninitialize(void)
{
	int i;
	
	// フォントテクスチャのリリース
	for(i = 0;i < font::COUNT_MAX;i++)
	{
		if(mpFontTexture[i]){
			mpFontTexture[i]->Release();
			mpFontTexture[i] = NULL;
		}
	}
	// スプライトオブジェクトの初期化
	for(i = 0;i < sprite::MAX;i++)
	{
		if(mpSprite[i]){
			delete mpSprite[i];
		}
	}


	releaseNotManagedObjects();

	// D3Dデバイスのリリース
	if(mpD3DDevice) {
		mpD3DDevice->Release();
		mpD3DDevice = NULL;
	}
	
	// Direct3Dオブジェクトのリリース
	if(mpD3D){
		mpD3D->Release();
		mpD3D = NULL;
	}
	
	// text queue のクリア
	
	while(!mTextQueue.empty())
	{
		delete mTextQueue.front();
		mTextQueue.pop();
	}

}// Uninitialize

// フォント関連メソッド ///////////////////////////////////////////////////////

// フォントロード   -----------------------------------------------------------
void ConsoleImpl::loadFont(void)
{
	
	HRESULT hr;
	for(int i = 0;i < font::COUNT_MAX;i++)
	{
		hr = D3DXCreateTextureFromFileExA(
			mpD3DDevice,
			font::FILE_PATH[i],
			D3DX_DEFAULT,
			D3DX_DEFAULT,
			0,
			0,
			mTextureFormat,
			D3DPOOL_MANAGED,
			D3DX_FILTER_NONE,
			D3DX_FILTER_NONE,
			0xff000000,
			NULL,
			NULL,
			&mpFontTexture[i]);

		if(FAILED(hr))
		{
			throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
		}
	}
}// LoadFont

// キャラクタテクスチャを使用して、文字列を表示する -----------------------
void ConsoleImpl::textDraw(int textureNo,float x,float y,float angleRad,float scale,COLOR color,
	char *pBuf)
{

	int cc = text::BUFFER_LENGTH;
	int ncc,ix,iy;
	
	float startx = x;
	float starty = y;
	
	D3DXVECTOR2 scaling,rotation_center,translation;
	
	float line = 0;
	RECT srect;
	
	
	
	float	dx = text::COLUMN_PITCH * scale * cosf(angleRad);
	float	dy = text::COLUMN_PITCH * scale * sinf(angleRad);
	
	scaling.x = scaling.y = scale;
	
	rotation_center.x = font::WIDTH / 2;
	rotation_center.y = font::HEIGHT / 2;
	
	// カラーキーのふちが抜けない現象を防止するため
	mpD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER , D3DTEXF_POINT);
	mpD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER , D3DTEXF_POINT);
	
	while(*pBuf && cc){
		ncc = *pBuf++;
		if (ncc > 0x1f && ncc < 0x80){
			ncc -= 0x20;
			
			ix = (ncc % 16) * font::WIDTH;
			iy = (ncc / 16) * font::HEIGHT;
			
			srect.top = iy;
			srect.left = ix;
			srect.right = ix + font::WIDTH; 
			srect.bottom = iy + font::HEIGHT;
			
			translation.x = x;
			translation.y = y;
			
			//			mPointDest.z = zOrder;
			
			mpD3DXSprite->Draw(
				mpFontTexture[textureNo],
				&srect,
				&scaling,
				&rotation_center,
				2 * D3DX_PI - angleRad,
				&translation,
				(D3DCOLOR)color
				);
			
			x += dx;
			y += dy;
			
		} else {
			
			if (ncc == 0xa){//LF
				line++;
				y = starty + line * text::LINE_PITCH * 
					scale * sinf((angleRad + D3DX_PI/2));
				x = startx + line * text::LINE_PITCH * 
					scale * cosf((angleRad + D3DX_PI/2 ));
			}
		}
		--cc;
	}
	return ;
	
}// TextDraw

// テキストキューの内容を出力 -----------------------------------------------
void ConsoleImpl::textOut()
{
	TextQueueData* text_q;  
	mpD3DXSprite->Begin();
	while(!mTextQueue.empty())
	{
		text_q = mTextQueue.front();
		mTextQueue.pop();
		textDraw(text_q->textureNo(),text_q->x(),text_q->y(),text_q->angeleRad(),text_q->scale(),text_q->color(),text_q->buffer());
		delete text_q;
	}
	mpD3DXSprite->End();
}// textOut

// キャラクターサーフェースを使用して、文字列を表示する -----------------------
void ConsoleImpl::print(const int textureNo,const float x,const float y,const float angleRad,const float scale,const COLOR color,
	const char *format,...)
{
	va_list varl;
	//char buf[text::BUFFER_LENGTH];
	
	/*	mAlpha = alpha;
	mAngleRad = angleRad;
	mScale = scale;
	mTextureNo = textureNo;
	mZOrder = zOrder;
	*/	

	TextQueueData* ptext_q = new TextQueueData(textureNo,x,y,angleRad,scale,color);
	
	va_start(varl,format);
	vsprintf(ptext_q->buffer(),format,varl);
	va_end(varl);
	
	mTextQueue.push(ptext_q);

//	textOut(textureNo,x,y,zOrder,alpha,angleRad,scale,color,buf);
}// Print

// 画面更新 ------------------------------------------------------------------
void ConsoleImpl::update(void)
{
	if(!isEnabled())
		return;

	// バックバッファの内容を表示
	mpD3DDevice->Present(NULL,NULL,NULL,NULL);
	startFrame();
//	Sleep(1);
	clearScreen();
//	Sleep(1);
	// スプライト描画
	for(Obj* pobj = Obj::List::moveTop();pobj != NULL;pobj = Obj::List::moveNext())
	{
		pobj->draw();
	}

	// テキスト描画

	textOut();

	endFrame();



}// update()

// 画面消去 ------------------------------------------------------------------
void ConsoleImpl::clearScreen(COLOR value)
{
	mpD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER ,value,1.0f,0);
}// clearScreen()
// 画面消去(色で埋める) -------------------------------------------------------
void ConsoleImpl::fillScreen(COLOR value)
{
	mpD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET ,value,1.0f,0);
}// fillScreen()

// フレーム開始 --------------------------------------------------------------
void ConsoleImpl::startFrame(void)
{
	// デバイスの状態をチェックする
	HRESULT hr = mpD3DDevice->TestCooperativeLevel();
	if(FAILED(hr)){
		mbD3DReady = false;
		switch(hr){
		case D3DERR_DEVICELOST:
#ifdef _DEBUG
			OutputDebugString("DEVICELOST\r\n");
#endif

			break;
		case D3DERR_DEVICENOTRESET:
#ifdef _DEBUG
			OutputDebugString("DEVICENOTRESET\r\n");
#endif
			releaseNotManagedObjects();
			
			if(FAILED(hr = mpD3DDevice->Reset(&mD3Dpp)))
			{
				throw FatalErrorException(DXGetErrorString8(hr),__FILE__,__LINE__);
			}
			
			initConsoleViewStyle();
			
			initNotManagedObjects();
			
			// デバイスの初期化
			initDeviceStates();
			
			mbD3DReady = true;
			break;
		}
	} else {
		mpD3DDevice->BeginScene();
	}
}// startFrame()
			
// フレーム終了 --------------------------------------------------------------
void ConsoleImpl::endFrame(void)
{
	mpD3DDevice->EndScene();
}// endFrame()


// スプライトのロード ---------------------------------------------------------
// 3Dのバーテックスバッファの生成部分は、ぷよーんさんのライブラリを参考にしています。
sprite::Sprite * const ConsoleImpl::createSprite(const sprite::Info * const pInfo)
{
	sprite::AbstractSprite * psprite = NULL;

	switch (pInfo->type)
	{
	case SPRITE2D:
		psprite = new Sprite2D(mpD3DDevice);
		break;
	case SPRITE3D:
		psprite = new Sprite3D(mpD3DDevice);
		break;
	case MESH:
		psprite = new SpriteMesh(mpD3DDevice);
		break;
	};

	if(NULL == psprite)
	{
		throw FatalErrorException("Sprite is not created",__FILE__,__LINE__);
	}

	psprite->load(pInfo,mTextureFormat,pInfo->transparentColor);
	return psprite;
}// createSprite()

//----------------------------------------------------------------------------
// TextQueueData -------------------------------------------------------------
//----------------------------------------------------------------------------

ConsoleImpl::TextQueueData::TextQueueData(const int textureNo,const float x,const float y,const float angleRad,const float scale,const COLOR color,const char *pBuffer)
{
	mTextureNo = textureNo;
	mX = x;
	mY = y;
	mAngleRad = angleRad;
	mScale = scale;
	mColor = color;

	if(pBuffer != NULL)
		strncpy(mpBuf,pBuffer,sizeof(mpBuf));
}// ConsoleImpl::TextQueueData::TextQueueData

ConsoleImpl::TextQueueData::~TextQueueData()
{
	;
}// ~TextQueueData


