#include "Mix/Private/Graphics/Utility/Common/TextPrinter.h"

#include "Mix/Graphics/IManager.h"
#include "Mix/Graphics/IDevice.h"
#include "Mix/Graphics/ITexture.h"

namespace Mix{ namespace Graphics{ namespace Utility{ namespace Common{

////////////////////////////////////////////////////////////////////////////////////////////////////
// 定数
////////////////////////////////////////////////////////////////////////////////////////////////////

const wchar_t* TextPrinter::FAILED_INIT = L"テキストプリンターの初期化に失敗";
const wchar_t* TextPrinter::FAILED_PROC = L"テキストプリンターの処理に失敗";

const Int32 TextPrinter::MIN_TEX_SIZE = 256;
const Int32 TextPrinter::MIN_TEX_COUNT = 1;
const Int32 TextPrinter::MIN_TAB_SIZE = 2;

////////////////////////////////////////////////////////////////////////////////////////////////////
// クラス TextPrinter
////////////////////////////////////////////////////////////////////////////////////////////////////

TextPrinter* TextPrinter::CreateInstance( Mix::Graphics::IDevice* pGraphicsDev, Int32 tabSize, Int32 pageSize, Int32 defPageNum )
{
	TextPrinter* pInterface = MIX_LIB_NEW_T( Mix::Memory::SECTION_GRAPHICS, TextPrinter, pGraphicsDev, tabSize, pageSize );

	if( pInterface != NULL )
	{
		if( pInterface->Initialize( defPageNum ) == False )
		{
			MIX_RELEASE( pInterface );
		}
	}

	return pInterface;
}

TextPrinter::TextPrinter( Mix::Graphics::IDevice* pGraphicsDev, Int32 tabSize, Int32 pageSize ) :
m_pDevice( NULL ),
m_TabSize( 0 ),
m_TexSize( 0 ),
m_TexSizeInv( 0.0f ),
m_TexOffset( 0.0f ),
m_TexPos( TextPrinter::TEX_MARGIN, TextPrinter::TEX_MARGIN ),
m_TexLine( TextPrinter::TEX_MARGIN ),
m_PageCount( 0 ),
m_SFModifyCharCount( 0 )
{
	MIX_ASSERT( pGraphicsDev != NULL );

	// グラフィックデバイス

	MIX_ADD_REF( pGraphicsDev );
	m_pDevice = pGraphicsDev;

	// タブ

	m_TabSize = max( TextPrinter::MIN_TAB_SIZE, tabSize );

	// テクスチャ

	m_TexSize = max( TextPrinter::MIN_TEX_SIZE, pageSize );
	m_TexSizeInv = MIX_FLOAT_RECIPROCAL( static_cast<Float32>( m_TexSize ) );

	switch( m_pDevice->GetShaderModel() )
	{
	case Mix::Graphics::SHADER_MODEL_3:
		m_TexOffset = 0.5f / static_cast<Float32>( m_TexSize );
		break;
	case Mix::Graphics::SHADER_MODEL_4:
	case Mix::Graphics::SHADER_MODEL_5:
		m_TexOffset = 0.0f;
		break;
	}

	// リスト

#ifdef _DEBUG

	m_PageList.Initialize( TextPrinter::PAGE_DEFSIZE, TextPrinter::PAGE_RESIZESTEP, L"TextPrinter/PageList" );
	m_PageSectList.Initialize( TextPrinter::PAGE_SECT_DEFSIZE, TextPrinter::PAGE_SECT_RESIZESTEP, L"TextPrinter/SectList" );
	m_CharList.Initialize( TextPrinter::CHAR_DEFSIZE, TextPrinter::CHAR_RESIZESTEP, L"TextPrinter/CharList" );
	m_QuadGroupList.Initialize( TextPrinter::QUAD_GROUP_DEFSIZE, TextPrinter::QUAD_GROUP_RESIZESTEP, L"TextPrinter/QuadGroupList" );
	m_QuadList.Initialize( TextPrinter::QUAD_DEFSIZE, TextPrinter::QUAD_RESIZESTEP, L"TextPrinter/QuadList" );
	m_SFCharInfoList.Initialize( SF_CHAR_DEFSIZE, SF_CHAR_RESIZESTEP, L"TextPrinter/SFCharInfoList" );
	m_SFLineInfoList.Initialize( SF_LINE_DEFSIZE, SF_LINE_RESIZESTEP, L"TextPrinter/SFLineInfoList" );

#else //_DEBUG

	m_PageList.Initialize( TextPrinter::PAGE_DEFSIZE, TextPrinter::PAGE_RESIZESTEP );
	m_PageSectList.Initialize( TextPrinter::PAGE_SECT_DEFSIZE, TextPrinter::PAGE_SECT_RESIZESTEP );
	m_CharList.Initialize( TextPrinter::CHAR_DEFSIZE, TextPrinter::CHAR_RESIZESTEP );
	m_QuadGroupList.Initialize( TextPrinter::QUAD_GROUP_DEFSIZE, TextPrinter::QUAD_GROUP_RESIZESTEP );
	m_QuadList.Initialize( TextPrinter::QUAD_DEFSIZE, TextPrinter::QUAD_RESIZESTEP );
	m_SFCharInfoList.Initialize( SF_CHAR_DEFSIZE, SF_CHAR_RESIZESTEP );
	m_SFLineInfoList.Initialize( SF_LINE_DEFSIZE, SF_LINE_RESIZESTEP );

#endif //_DEBUG
}

TextPrinter::~TextPrinter( void )
{
	for( UInt32 i = 0; i < m_PageList.GetCount(); i++ )
	{
		MIX_RELEASE( m_PageList[i].pTexture );
	}

	for( UInt32 i = 0; i < m_PageSectList.GetCount(); i++ )
	{
		MIX_RELEASE( m_PageSectList[i].pFont );
	}

	m_CharList.Clear();
	m_QuadGroupList.Clear();
	m_QuadList.Clear();

	MIX_RELEASE( m_pDevice );
}

Boolean TextPrinter::Initialize( Int32 defPageNum )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 最初から持っているテクスチャを作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	defPageNum = max( TextPrinter::MIN_TEX_COUNT, defPageNum );

	for( Int32 i = 0; i < defPageNum; i++ )
	{
		Mix::Graphics::ITexture* pTexture = CreateTexture();
		if( pTexture == NULL )
		{
			MIX_LOG_ERROR( L"%s : 初期のページテクスチャが作成できませんでした : Name[TextPrinter]", TextPrinter::FAILED_INIT );
			return False;
		}

		TextPrinter::PAGE* pPage = m_PageList.Add();
		if( pPage == NULL )
		{
			MIX_LOG_ERROR( L"%s : %s : Name[TextPrinter]", TextPrinter::FAILED_INIT,  Mix::STR_OUTOFMEMORY );
			MIX_RELEASE( pTexture );
			return False;
		}

		pPage->pTexture = pTexture;
		pPage->sectStart = 0;
		pPage->sectCount = 0;
	}

	return True;
}

Mix::Point TextPrinter::Measure( Mix::Graphics::Utility::IFont* pFont, const wchar_t* pStr ) const
{
	MIX_ASSERT( pFont != NULL );
	MIX_ASSERT( pStr != NULL );

	Int32 height = pFont->GetHeight();

	if( height % 2 != 0 )
	{
		height += 1;
	}

	Int32 halfHeight = height >> 1;
	Int32 halfHeightWithBorder = halfHeight + pFont->GetBorderSize();
	Int32 tabWidthI= halfHeight * m_TabSize;

	Mix::Point pos = Mix::Point::Zero();
	Mix::Point size = Mix::Point::Zero();
	Int32 line = 0;

	for( UInt32 i = 0; pStr[i] != L'\0'; i++ )
	{
		wchar_t code = pStr[i];
		Mix::Graphics::Utility::IFont::GLYPH fontGlyph;

		if( code == L' ' )
		{
			pos.x += halfHeight;
			pos.y = line + halfHeight;
		}
		else if( code == L'　' )
		{
			pos.x += height;
			pos.y = line + height;
		}
		else if( code == L'\t' )
		{
			pos.x += pos.x % tabWidthI;
			pos.y = line + height;
		}
		else if( code == L'\r' )
		{
			;
		}
		else if( code == L'\n' )
		{
			pos.x = 0;
			pos.y = 0;

			line += height;
		}
		else if( pFont->GetGlyph( code, fontGlyph ) == True )
		{
			pos.x = ( halfHeightWithBorder >= fontGlyph.cellWidth )? ( pos.x + halfHeight ) : ( pos.x + height );
			pos.y = line + height;
		}

		if( size.x < pos.x ) { size.x = pos.x; }
		if( size.y < pos.y ) { size.y = pos.y; }
	}

	return size;
}

Boolean TextPrinter::Append( Mix::Graphics::Utility::IFont* pFont, const Mix::Point& pos, const wchar_t* pStr )
{
	if( ( pFont == NULL ) || ( pStr == NULL ) || ( ::wcslen( pStr ) == 0 ) )
	{
		return False;
	}

	TextPrinter::PAGE* pPage = NULL;
	TextPrinter::PAGE_SECTION* pPageSect = NULL;
	TextPrinter::QUAD_GROUP* pQuadGroup = NULL;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	pPage = GetCurrentPage();
	if( pPage == NULL )
	{
		pPage = AddPage( pFont );
		if( pPage == NULL )
		{
			return False;
		}
	}

	pPageSect = AddPageSection( pFont );
	if( pPageSect == NULL )
	{
		return False;
	}

	m_QuadGroupList.Clear();
	m_QuadList.Clear();

	pQuadGroup = m_QuadGroupList.Add();
	pQuadGroup->pTexture = pPage->pTexture;
	pQuadGroup->start = 0;
	pQuadGroup->count = 0;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	Int32 bpx = pos.x;
	Int32 bpy = pos.y;

	Int32 height = pFont->GetHeight();

	if( height % 2 != 0 )
	{
		height += 1;
	}

	Int32 halfHeight = height >> 1;
	Int32 halfHeightWithBorder = halfHeight + pFont->GetBorderSize();
	Int32 tabWidthI= halfHeight * m_TabSize;

	Int32 ox = 0;
	Int32 oy = 0;

	for( UInt32 i = 0; pStr[i] != L'\0'; i++ )
	{
		wchar_t code = pStr[i];
		Mix::Graphics::Utility::IFont::GLYPH fontGlyph;

		if( code == L' ' )
		{
			ox += halfHeight;
		}
		else if( code == L'　' )
		{
			ox += height;
		}
		else if( code == L'\t' )
		{
			ox += ox % tabWidthI;
		}
		else if( code == L'\r' )
		{
			;
		}
		else if( code == L'\n' )
		{
			ox = 0;
			oy += height;
		}
		else if( pFont->GetGlyph( code, fontGlyph ) == True )
		{
			//イメージを追加
			AddImage(	&pPage,
						&pPageSect,
						&pQuadGroup,
						bpx + ox + fontGlyph.x,
						bpy + oy + fontGlyph.y,
						fontGlyph.width,
						fontGlyph.height,
						pFont,
						fontGlyph );

			//座標を進める
			ox = ( halfHeightWithBorder >= fontGlyph.cellWidth )? ( ox + halfHeight ) : ( ox + height );
		}
	}

	return True;
}

Boolean TextPrinter::Append( Mix::Graphics::Utility::IFont* pFont, const Mix::Rectangle& rect, const wchar_t* pStr, UInt32 flags )
{
	if( ( pFont == NULL ) || ( pStr == NULL ) || ( ::wcslen( pStr ) == 0 ) )
	{
		//不正な引数
		return False;
	}

	Int32 fontHeight = pFont->GetHeight();

	if( fontHeight % 2 != 0 )
	{
		//偶数にする
		fontHeight += 1;
	}

	Int32 fontHalfHeight = fontHeight >> 1;

	Int32 fontHalfHeightWithBorder = fontHalfHeight + pFont->GetBorderSize();
	Int32 tabWidth = fontHalfHeight * m_TabSize;

	Int32 bx = rect.x;
	Int32 by = rect.y;
	Int32 bw = rect.width;
	Int32 bh = rect.height;

	if( ( fontHeight >= bw ) || ( fontHeight >= bh ) )
	{
		//極端に小さい矩形は描画しない
		return False;
	}

	Boolean bContinue = True;
	const wchar_t* pCode = &( pStr[0] );
	Int32 ox = 0;
	Int32 oy = 0;
	Int32 tabStep;
	Mix::Graphics::Utility::IFont::GLYPH fontGlyph;

	TextPrinter::PAGE* pPage;
	TextPrinter::PAGE_SECTION* pPageSect;
	TextPrinter::QUAD_GROUP* pQuadGroup;
	const TextPrinter::SF_LINE_INFO* pLineInfo;
	const TextPrinter::SF_LINE_INFO* pLineInfoEnd;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	//リセット
	m_SFCharInfoList.Clear();
	m_SFLineInfoList.Clear();
	m_SFModifyCharCount = 0;

	//文字描画用の情報を作成
	while( bContinue == True )
	{
		if( *pCode == L'\0' )
		{
			bContinue = False;
		}
		else if( *pCode == L' ' )
		{
			if( bw <= ( ox + fontHalfHeight ) )
			{
				ox = 0;
				oy += fontHeight;
			}
			else
			{
				ox += fontHalfHeight;
			}
		}
		else if( *pCode == L'　' )
		{
			if( bw <= ( ox + fontHeight ) )
			{
				ox = 0;
				oy += fontHeight;
			}
			else
			{
				ox += fontHeight;
			}
		}
		else if( *pCode == L'\t' )
		{
			tabStep = ox % tabWidth;

			if( bw <= ( ox + tabStep ) )
			{
				ox = 0;
				oy += fontHeight;
			}
			else
			{
				ox += tabStep;
			}
		}
		else if( *pCode == L'\r' )
		{
			//キャリッジリターン
			;
		}
		else if( *pCode == L'\n' )
		{
			//改行 : 行を追加
			SF_AddLine();

			ox = 0;
			oy += fontHeight;
		}
		else if( pFont->GetGlyph( *pCode, fontGlyph ) == True )
		{
			if( bw <= ( ox + fontGlyph.cellWidth ) )
			{
				if( MIX_TESTBIT( flags, Mix::Graphics::Utility::SF_WORDBREAK ) == Mix::Graphics::Utility::SF_WORDBREAK )
				{
					//行を追加
					if( bh > ( oy + fontHeight + fontHeight ) )
					{
						SF_AddLine();

						ox = 0;
						oy += fontHeight;

						//極端に小さい矩形( 一文字が描画できない矩形 )を指定されている場合に処理するため、
						//一つ前に戻し、次も同じ文字を処理させるようにする
						pCode--;
					}
					else
					{
						bContinue = False;
					}
				}
				else
				{
					if( MIX_TESTBIT( flags, Mix::Graphics::Utility::SF_HCENTER ) == Mix::Graphics::Utility::SF_HCENTER )
					{
						//文字を追加( 文字のカットは HCENTER で行う );
						SF_AddChar( bx + ox, by + oy, *pCode, fontGlyph );
					}

					ox = ( fontHalfHeightWithBorder >= fontGlyph.cellWidth )? ( ox + fontHalfHeight ) : ( ox + fontHeight );
				}
			}
			else
			{
				//文字を追加
				SF_AddChar( bx + ox, by + oy, *pCode, fontGlyph );

				ox = ( fontHalfHeightWithBorder >= fontGlyph.cellWidth )? ( ox + fontHalfHeight ) : ( ox + fontHeight );
			}
		}
		else
		{
			//サポートしていない文字は半角スペースを入れてしまう
			if( bw <= ( ox + fontHalfHeight ) )
			{
				ox = 0;
				oy += fontHeight;
			}
			else
			{
				ox += fontHalfHeight;
			}
		}

		if( bh <= ( oy + fontHeight ) )
		{
			bContinue = False;
		}

		pCode++;
	}

	if( ( m_SFLineInfoList.GetCount() == 0 ) || ( m_SFCharInfoList.GetCount() == 0 ) )
	{
		//何も無かった
		return False;
	}

	if( MIX_TESTBIT( flags, Mix::Graphics::Utility::SF_HCENTER ) == Mix::Graphics::Utility::SF_HCENTER )
	{
		//水平方向のセンタリング
		SF_DoCenterH( bw );
	}

	if( MIX_TESTBIT( flags, Mix::Graphics::Utility::SF_VCENTER ) == Mix::Graphics::Utility::SF_VCENTER )
	{
		//垂直方向のセンタリング
		SF_DoCenterV( bh );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	pPage = GetCurrentPage();
	if( pPage == NULL )
	{
		pPage = AddPage( pFont );
		if( pPage == NULL )
		{
			return False;
		}
	}

	pPageSect = AddPageSection( pFont );
	if( pPageSect == NULL )
	{
		return False;
	}

	m_QuadGroupList.Clear();
	m_QuadList.Clear();

	pQuadGroup = m_QuadGroupList.Add();
	pQuadGroup->pTexture = pPage->pTexture;
	pQuadGroup->start = 0;
	pQuadGroup->count = 0;

	pLineInfo = m_SFLineInfoList.GetConstBeginPtr();
	pLineInfoEnd = pLineInfo + m_SFLineInfoList.GetCount();

	while( pLineInfo != pLineInfoEnd )
	{
		if( pLineInfo->charCount > 0 )
		{
			const TextPrinter::SF_CHARACTER_INFO* pCharInfo = &( m_SFCharInfoList[pLineInfo->charStart] );
			const TextPrinter::SF_CHARACTER_INFO* pCharInfoEnd = pCharInfo + pLineInfo->charCount;

			while( pCharInfo != pCharInfoEnd )
			{
				const Mix::Rectangle& bounds = pCharInfo->bounds;

				//イメージを追加
				AddImage(	&pPage,
							&pPageSect,
							&pQuadGroup,
							bounds.x, bounds.y, bounds.width, bounds.height,
							pFont,
							pCharInfo->fontGlyph );

				pCharInfo++;
			}
		}

		pLineInfo++;
	}

	return True;
}

const Mix::ContainerT<TextPrinter::QUAD_GROUP, Mix::Memory::SECTION_GRAPHICS>& TextPrinter::GetQuadGroups( void ) const
{
	return m_QuadGroupList;
}

const Mix::ContainerT<TextPrinter::QUAD, Mix::Memory::SECTION_GRAPHICS>& TextPrinter::GetQuads( void ) const
{
	return m_QuadList;
}

void TextPrinter::Execute( void )
{
	if( m_PageCount == 0 )
	{
		return;
	}

	const TextPrinter::PAGE* pPage = m_PageList.GetConstBeginPtr();
	const TextPrinter::PAGE* pPageEnd = pPage + m_PageCount;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// テクスチャに書き込む
	////////////////////////////////////////////////////////////////////////////////////////////////////

	while( pPage != pPageEnd )
	{
		Mix::Graphics::ITexture::LOCK lock;

		if( pPage->pTexture->Lock( lock ) == True )
		{
			TextPrinter::PAGE_SECTION* pPageSect = &( m_PageSectList[pPage->sectStart] );
			TextPrinter::PAGE_SECTION* pPageSectEnd = pPageSect + pPage->sectCount;

			UInt32* pTexBits = static_cast<UInt32*>( lock.bits );
			UInt32 dstPitch = ( lock.pitch >> 2 );

			while( pPageSect != pPageSectEnd )
			{
				const TextPrinter::CHARACTER* pChar = &( m_CharList[pPageSect->charStart] );
				const TextPrinter::CHARACTER* pCharEnd = pChar + pPageSect->charCount;

				while( pChar != pCharEnd )
				{
					const Mix::Point& texPos = pChar->texPos;
					const Mix::Graphics::Utility::IFont::GLYPH& fontGlyph = pChar->fontGlyph;

					UInt32* pDstBase;
					UInt32* pDst;
					UInt32* pDstEnd;

					const UInt16* pSrcBase;
					const UInt16* pSrc;
					UInt32 srcPitch;

					Int32 y;

					UInt32 tint;
					UInt32 alpha;

					//クリア
					pDstBase = pTexBits + ( ( texPos.y - TextPrinter::TEX_MARGIN ) * dstPitch ) + ( texPos.x - TextPrinter::TEX_MARGIN );
					for( y = 0; y < ( fontGlyph.height + TextPrinter::TEX_MARGIN2 ); y++ )
					{
						pDst = pDstBase;
						pDstEnd = ( pDst + ( fontGlyph.width + TextPrinter::TEX_MARGIN2 ) );

						while( pDst != pDstEnd ) { *pDst++ = 0x00000000; }

						pDstBase += dstPitch;
					}

					//書き込む
					pSrcBase = static_cast<const UInt16*>( fontGlyph.pImg );
					srcPitch = fontGlyph.width;
					pDstBase = pTexBits + ( texPos.y * dstPitch ) + texPos.x;
					for( y = 0; y < fontGlyph.height; y++ )
					{
						pSrc = pSrcBase;
						pDst = pDstBase;
						pDstEnd = ( pDst + fontGlyph.width );

						while( pDst != pDstEnd )
						{
							tint = ( *pSrc & 0xFF00 ) >> 8;
							alpha = ( *pSrc & 0x00FF );

							*pDst++ = ( alpha << 24 ) | ( tint << 16 ) | ( tint << 8 ) | tint;
							pSrc++;
						}

						pSrcBase += srcPitch;
						pDstBase += dstPitch;
					}

					pChar++;
				}

				MIX_RELEASE( pPageSect->pFont );

				pPageSect++;
			}

			pPage->pTexture->Unlock();
		}

		pPage++;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// クリア
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_TexPos = Mix::Point( TextPrinter::TEX_MARGIN, TextPrinter::TEX_MARGIN );
	m_TexLine = TextPrinter::TEX_MARGIN;

	m_PageCount = 0;
	m_PageSectList.Clear();
	m_CharList.Clear();

	m_QuadGroupList.Clear();
	m_QuadList.Clear();
}

UInt32 TextPrinter::GetTextureCount( void ) const
{
	return m_PageList.GetCount();
}

Mix::Graphics::ITexture* TextPrinter::GetTexturePtr( UInt32 index ) const
{
	if( m_PageList.GetCount() <= index )
	{
		return NULL;
	}

	return m_PageList[index].pTexture;
}

TextPrinter::PAGE* TextPrinter::GetCurrentPage( void )
{
	if( m_PageCount == 0 )
	{
		return NULL;
	}

	return &( m_PageList[m_PageCount - 1] );
}

TextPrinter::PAGE* TextPrinter::AddPage( Mix::Graphics::Utility::IFont* pFont )
{
	TextPrinter::PAGE* pPage;
	TextPrinter::PAGE_SECTION* pPageSect;

	if( m_PageCount == m_PageList.GetCount() )
	{
		Mix::Graphics::ITexture* pTexture = CreateTexture();
		if( pTexture == NULL )
		{
			MIX_LOG_ERROR( L"%s : ページのテクスチャが作成できませんでした : Name[TextPrinter]", TextPrinter::FAILED_PROC );
			return NULL;
		}

		pPage = m_PageList.Add();
		pPage->pTexture = pTexture;
	}
	else
	{
		pPage = &( m_PageList[m_PageCount] );
	}

	//ページの初期化
	pPage->sectStart = m_PageSectList.GetCount();
	pPage->sectCount = 0;
	m_PageCount++;

	//セクションの追加＆初期化
	pPageSect = m_PageSectList.Add();
	if( pPageSect != NULL )
	{
		MIX_ADD_REF( pFont );

		pPageSect->pFont = pFont;
		pPageSect->charStart = m_CharList.GetCount();
		pPageSect->charCount = 0;

		pPage->sectCount = 1;
	}

	return pPage;
}

TextPrinter::PAGE_SECTION* TextPrinter::AddPageSection( Mix::Graphics::Utility::IFont* pFont )
{
	MIX_ASSERT( pFont != NULL );
	MIX_ASSERT( m_PageCount > 0 );

	if( ( m_PageSectList.GetCount() > 0 ) &&
		( m_PageSectList[m_PageSectList.GetCount() - 1].pFont == pFont ) )
	{
		return &( m_PageSectList[m_PageSectList.GetCount() - 1] );
	}

	TextPrinter::PAGE* pPage = &( m_PageList[m_PageCount - 1] );
	TextPrinter::PAGE_SECTION* pPageSect = m_PageSectList.Add();

	MIX_ASSERT( pPageSect != NULL );

	//セクション数をインクリメント
	pPage->sectCount++;

	//セクションを初期化
	MIX_ADD_REF( pFont );
	pPageSect->pFont = pFont;
	pPageSect->charStart = m_CharList.GetCount();
	pPageSect->charCount = 0;

	return pPageSect;
}

void TextPrinter::AddImage(	TextPrinter::PAGE** ppPage,
							TextPrinter::PAGE_SECTION** ppPageSect,
							TextPrinter::QUAD_GROUP** ppQuadGroup,
							Int32 dx, Int32 dy, Int32 dw, Int32 dh,
							Mix::Graphics::Utility::IFont* pFont,
							const Mix::Graphics::Utility::IFont::GLYPH& fontGlyph )
{
	MIX_ASSERT( ppPage != NULL );
	MIX_ASSERT( ppPageSect != NULL );
	MIX_ASSERT( ppQuadGroup != NULL );
	MIX_ASSERT( *ppPage != NULL );
	MIX_ASSERT( *ppPageSect != NULL );
	MIX_ASSERT( *ppQuadGroup != NULL );
	MIX_ASSERT( pFont != NULL );

	TextPrinter::CHARACTER* pChar;
	TextPrinter::QUAD* pQuad;
	Float32 dl, dt, dr, db;
	Float32 tl, tt, tr, tb;
	Mix::Vector2* points;
	Mix::Vector2* texCoords;

	if( ( m_TexPos.x + fontGlyph.width + TextPrinter::TEX_MARGIN ) >= m_TexSize )
	{
		//横をはみ出した
		m_TexPos.x = TextPrinter::TEX_MARGIN;
		m_TexPos.y = m_TexLine;
	}

	if( ( m_TexPos.y + fontGlyph.height + TextPrinter::TEX_MARGIN ) >= m_TexSize )
	{
		//縦をはみ出した

		TextPrinter::PAGE* pNewPage = AddPage( pFont );
		TextPrinter::PAGE_SECTION* pNewPageSect = AddPageSection( pFont );

		MIX_ASSERT( pNewPage != NULL );
		MIX_ASSERT( pNewPageSect != NULL );

		( *ppPage ) = pNewPage;
		( *ppPageSect ) = pNewPageSect;

		if( ( *ppQuadGroup )->count > 0 )
		{
			( *ppQuadGroup ) = m_QuadGroupList.Add();
			( *ppQuadGroup )->start = m_QuadList.GetCount();
			( *ppQuadGroup )->count = 0;
		}

		( *ppQuadGroup )->pTexture = pNewPage->pTexture;

		m_TexPos.x = TextPrinter::TEX_MARGIN;
		m_TexPos.y = TextPrinter::TEX_MARGIN;
		m_TexLine = TextPrinter::TEX_MARGIN;
	}

	//キャラクターを追加
	pChar = m_CharList.Add();
	pChar->texPos = m_TexPos;
	pChar->fontGlyph = fontGlyph;
	( *ppPageSect )->charCount++;

	//クワッドを追加
	pQuad = m_QuadList.Add();
	( *ppQuadGroup )->count++;

	//描画座標
	dl = static_cast<Float32>( dx );
	dt = static_cast<Float32>( dy );
	dr = static_cast<Float32>( dx + dw );
	db = static_cast<Float32>( dy + dh );

	points = pQuad->points;

	points[0].Set( dl, dt );
	points[1].Set( dr, dt );
	points[2].Set( dr, db );
	points[3].Set( dl, db );

	//テクスチャ座標
	tl = static_cast<Float32>( m_TexPos.x ) * m_TexSizeInv + m_TexOffset;
	tt = static_cast<Float32>( m_TexPos.y ) * m_TexSizeInv + m_TexOffset;
	tr = static_cast<Float32>( m_TexPos.x + fontGlyph.width ) * m_TexSizeInv + m_TexOffset;
	tb = static_cast<Float32>( m_TexPos.y + fontGlyph.height ) * m_TexSizeInv + m_TexOffset;

	texCoords = pQuad->texCoords;

	texCoords[0].Set( tl, tt );
	texCoords[1].Set( tr, tt );
	texCoords[2].Set( tr, tb );
	texCoords[3].Set( tl, tb );

	//テクスチャ座標を進める
	m_TexPos.x += ( fontGlyph.width + TextPrinter::TEX_MARGIN );
	m_TexLine = max( m_TexLine, ( m_TexPos.y + fontGlyph.height + TextPrinter::TEX_MARGIN ) );
}

Mix::Graphics::ITexture* TextPrinter::CreateTexture( void )
{
	Mix::StringW tempStr;
	Mix::Graphics::ITexture* pTexture = NULL;

	tempStr.Sprintf( L"TextPrinter/Page_%d", m_PageList.GetCount() );
	if( m_pDevice->CreateDynamicPlaneTexture( m_TexSize, m_TexSize, Mix::Graphics::FMT_R8G8B8A8, &pTexture, tempStr.GetConstPtr() ) == False )
	{
		return NULL;
	}

	return pTexture;
}

void TextPrinter::SF_AddChar( Int32 x, Int32 y, wchar_t code, const Mix::Graphics::Utility::IFont::GLYPH& fontGlyph )
{
	UInt32 lineIndex;
	TextPrinter::SF_LINE_INFO* pLineInfo;
	TextPrinter::SF_CHARACTER_INFO* pCharInfo;

	if( m_SFLineInfoList.GetCount() == 0 )
	{
		lineIndex = 0;

		pLineInfo = m_SFLineInfoList.Add();
		pLineInfo->charStart = 0;
		pLineInfo->charCount = 0;
	}
	else
	{
		lineIndex = m_SFLineInfoList.GetCount() - 1;
		pLineInfo = &( m_SFLineInfoList[lineIndex] );
	}

	pLineInfo->charCount++;

	pCharInfo = m_SFCharInfoList.Add();
	pCharInfo->fontGlyph = fontGlyph;
	pCharInfo->bounds.x = x + fontGlyph.x;
	pCharInfo->bounds.y = y + fontGlyph.y;
	pCharInfo->bounds.width = fontGlyph.width;
	pCharInfo->bounds.height = fontGlyph.height;
	pCharInfo->cellBounds.x = x;
	pCharInfo->cellBounds.y = y;
	pCharInfo->cellBounds.width = fontGlyph.cellWidth;
	pCharInfo->cellBounds.height = fontGlyph.cellHeight;

	m_SFModifyCharCount++;
}

void TextPrinter::SF_AddLine( void )
{
	TextPrinter::SF_LINE_INFO* pLineInfo = m_SFLineInfoList.Add();

	pLineInfo->charStart = m_SFCharInfoList.GetCount();
	pLineInfo->charCount = 0;
}

void TextPrinter::SF_DoCenterH( Int32 width )
{
	if( m_SFModifyCharCount == 0 )
	{
		return;
	}

	TextPrinter::SF_LINE_INFO* pLineInfo;
	TextPrinter::SF_LINE_INFO* pLineInfoEnd;
	TextPrinter::SF_CHARACTER_INFO* charInfoList;
	TextPrinter::SF_CHARACTER_INFO* pCharInfo;
	TextPrinter::SF_CHARACTER_INFO* pCharInfoEnd;
	UInt32 ct;
	UInt32 cb;
	Int32 left;
	Int32 right;
	Int32 len;
	Int32 offset;

	charInfoList = m_SFCharInfoList.GetBeginPtr();
	pLineInfo = m_SFLineInfoList.GetBeginPtr();
	pLineInfoEnd = m_SFLineInfoList.GetEndPtr();

	while( pLineInfo != pLineInfoEnd )
	{
		left = INT_MAX;
		right = 0;

		if( pLineInfo->charCount > 0 )
		{
			//一行の横の長さを計る
			pCharInfo = &( charInfoList[pLineInfo->charStart] );
			pCharInfoEnd = ( pCharInfo + pLineInfo->charCount );
			while( pCharInfo != pCharInfoEnd )
			{
				left = min( left, pCharInfo->cellBounds.x );
				right = max( right, pCharInfo->cellBounds.GetRight() );
				pCharInfo++;
			}

			//一行の長さ
			len = ( right - left );

			//はみ出していた場合は、後の文字を削る
			if( width <= len )
			{
				ct = pLineInfo->charStart;
				cb = ( ct + pLineInfo->charCount - 1 );

				for( ;; )
				{
					len -= charInfoList[cb].cellBounds.width;
					cb--;
					m_SFModifyCharCount--;

					if( ( width > len ) || ( ct > cb ) )
					{
						break;
					}
				}

				pLineInfo->charStart = ct;
				pLineInfo->charCount = ( ct <= cb )? ( cb - ct + 1 ) : 0;
			}

			//中央によせる
			if( pLineInfo->charCount > 0 )
			{
				pCharInfo = &( charInfoList[pLineInfo->charStart] );
				pCharInfoEnd = ( pCharInfo + pLineInfo->charCount );
				offset = ( width - len ) >> 1;
				while( pCharInfo != pCharInfoEnd )
				{
					pCharInfo->bounds.x += offset;
					pCharInfo->cellBounds.x += offset;
					pCharInfo++;
				}
			}
		}

		pLineInfo++;
	}
}

void TextPrinter::SF_DoCenterV( Int32 height )
{
	TextPrinter::SF_LINE_INFO* pLineInfo;
	TextPrinter::SF_LINE_INFO* pLineInfoEnd;
	TextPrinter::SF_CHARACTER_INFO* charInfoList;
	TextPrinter::SF_CHARACTER_INFO* pCharInfo;
	TextPrinter::SF_CHARACTER_INFO* pCharInfoEnd;
	Int32 top;
	Int32 bottom;
	Int32 offset;

	top = INT_MAX;
	bottom = 0;

	charInfoList = m_SFCharInfoList.GetBeginPtr();
	pLineInfo = m_SFLineInfoList.GetBeginPtr();
	pLineInfoEnd = m_SFLineInfoList.GetEndPtr();

	while( pLineInfo != pLineInfoEnd )
	{
		pCharInfo = &( charInfoList[pLineInfo->charStart] );
		pCharInfoEnd = ( pCharInfo + pLineInfo->charCount );
		while( pCharInfo != pCharInfoEnd )
		{
			top = min( top, pCharInfo->cellBounds.y );
			bottom = max( bottom, pCharInfo->cellBounds.GetBottom() );

			pCharInfo++;
		}

		pLineInfo++;
	}

	offset = ( height - ( bottom - top ) ) >> 1;

	pLineInfo = m_SFLineInfoList.GetBeginPtr();
	pLineInfoEnd = m_SFLineInfoList.GetEndPtr();
	while( pLineInfo != pLineInfoEnd )
	{
		pCharInfo = &( charInfoList[pLineInfo->charStart] );
		pCharInfoEnd = ( pCharInfo + pLineInfo->charCount );
		while( pCharInfo != pCharInfoEnd )
		{
			pCharInfo->bounds.y += offset;
			pCharInfo->cellBounds.y += offset;
			pCharInfo++;
		}

		pLineInfo++;
	}
}

}}}}
