⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 font.cpp

📁 一个自己写的游戏引擎,用DirectX 写成
💻 CPP
字号:
//--------------------------------------------------
//  Desc: Texture Font
//  Author: artsylee/2006.11.03
//--------------------------------------------------
#include "../stdafx.h"
#include "Font.h"
#include "Log.h"
#include "Common.h"
#include "FontTexture.h"
#include "Interface.h"
#include "TextureManager.h"

//--------------------------------------------------
// 是否限定纹理尺寸为2的N次方
//--------------------------------------------------
#define _TEXTURE_POWER_2

GFont::GFont()
{
	m_hFont = NULL;
	m_UpdateTime = 0;
}

GFont::~GFont()
{
	Release();
}

void GFont::Release()
{
	m_UpdateTime = 0;
	if(m_hFont)
	{
		DeleteObject(m_hFont);
	}

	FontTextureItor itor = m_FontTextureMap.begin();
	while(itor!= m_FontTextureMap.end())
	{
		::DestroyTexture((*itor).first);
		++itor;
	}
	m_FontTextureMap.clear();
}

//---------------------------------------------------
// 创建字体
//---------------------------------------------------
bool GFont::CreateFont(const char *szFontName, DWORD height, DWORD width, DWORD weight)
{
	if(szFontName==NULL)
	{
		return false;
	}
	if(m_hFont!=NULL || m_FontTextureMap.size())
	{
		Release();
	}

	m_hFont = ::CreateFont(height, 
						 width, 
						 0, 
						 0, 
						 weight, 
						 0, 
						 FALSE, 
						 FALSE, 
						 DEFAULT_CHARSET, 
						 OUT_DEFAULT_PRECIS, 
						 CLIP_DEFAULT_PRECIS, 
						 DEFAULT_QUALITY, 
						 DEFAULT_PITCH|FF_SWISS, 
						// FF_DONTCARE,
						 szFontName);
	if(m_hFont==NULL)
	{
		WriteLog(INFO_ERROR, "Create font fail[%s]", szFontName);
		return false;
	}
	strcpy(m_FontFamily, szFontName);
	m_FontWidth = width;
	m_FontHeight = height;
	m_FontWeight = weight;
	m_LineCount = 70;
	m_LineHeight = 20;
/*
	for(int i=0; i<MAX_FONT_TEXTURE; i++)
	{
		CFontTexture * pTexture = new CFontTexture;
		pTexture->CreateFontTexture(FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT);
		TextureHandle hTex = g_pTextureManager->InsertTexture(pTexture, MM_KEEPINMEMORY);
		m_FontTextureMap.insert(FontTextureValue(hTex, pTexture));
	}
*/
	return true;
}

//---------------------------------------------------
// 格式化输出
//---------------------------------------------------
int GFont::DrawText(int x, int y, DWORD color, const char *pString, ...)
{
	char *szText = new char[strlen(pString) + 256];
	char *szBack = szText;

	va_list va;
	va_start(va, pString);
	vsprintf(szText, pString, va);
	va_end(va);

	if(szText[0]==0)
	{
		delete [] szBack;
		return 0;
	}
	int TotalLen, CurLen, LeaveLen;
	int Ascii = 0, Chars = 0;
	int XPos = x;
	char Tmp[256];
	int nLine = 0;
	TotalLen = strlen(szText);

	while(szText < szBack + TotalLen)
	{
		Ascii=0;
		Chars=0;
		XPos=x;
		memset(Tmp, 0, 256);

		LeaveLen = TotalLen - (int)(szText - szBack);
		if(LeaveLen > (int)m_LineCount) 
			CurLen = (int)m_LineCount;
		else 
			CurLen = LeaveLen;

		while((Chars < CurLen) && *szText)
		{
			//控制字符串处理

			Tmp[Chars] = *szText;
			szText++;
			Chars++;

			if((unsigned char)Tmp[Chars-1]<128)
				Ascii=1-Ascii;
		}
		// ASCII数量为单数
		if(Ascii==1 && szText < szBack + TotalLen)
		{
			szText--;
			Tmp[Chars-1]=0;
		}

//_Show:
		nLine++;
		TextOut(XPos, y, color, Tmp);
		y += m_LineHeight;
	}

	delete [] szBack;
	return nLine;
}

//---------------------------------------------------
// 获取空闲纹理
//---------------------------------------------------
DWORD GFont::GetIdleTexture()
{
	// 空的
	FontTextureItor itor = m_FontTextureMap.begin();
	while(itor != m_FontTextureMap.end())
	{
		if((*itor).second->IsEmpty())
		{
			return (*itor).first;
		}
		itor++;
	}

	// 最长时间不使用的
	DWORD last = 0;
	DWORD hTex;
	itor = m_FontTextureMap.begin();
	while(itor != m_FontTextureMap.end())
	{
		DWORD updatetm = (*itor).second->GetLastUseTime();
		if(last == 0)
		{
			last = updatetm;
			hTex = (*itor).first;
		}
		else
		{
			if(last > updatetm)
			{
				last = updatetm;
				hTex = (*itor).first;
			}
		}
		itor++;
	}
	return hTex;
}

//---------------------------------------------------
// 输出到纹理
//---------------------------------------------------
void GFont::TextOut(int x, int y, DWORD color, const char *pString)
{
	if(pString[0]=='\0')
		return;
	DWORD dwNow = ::timeGetTime();
	FontTextureItor itor = m_FontTextureMap.begin();
	while(itor != m_FontTextureMap.end())
	{
		if((*itor).second->Compare(pString))
		{
			::Render((*itor).first, x, y, NULL, color);
			(*itor).second->SetLastUseTime(dwNow);
			return;
		}
		itor++;
	}
	DWORD hFind = INVALID_HANDLE;
	CFontTexture * pTexture = NULL;
	RECT rc = GetStringRect(pString);
	if(m_FontTextureMap.size()>MAX_FONT_TEXTURE)
	{
		// 取空闲纹理
		hFind = GetIdleTexture();
		itor = m_FontTextureMap.find(hFind);
		pTexture = (*itor).second;
		pTexture->Release();

#ifdef _TEXTURE_POWER_2
		int texWidth = FONT_TEXTURE_WIDTH;
		int texHeight = FONT_TEXTURE_HEIGHT;
		if(rc.right>FONT_TEXTURE_WIDTH)
			texWidth = FONT_TEXTURE_WIDTH*2;
		if(rc.bottom>FONT_TEXTURE_HEIGHT)
			texHeight = FONT_TEXTURE_HEIGHT*2;
		pTexture->CreateFontTexture(texWidth, texHeight);
#else
		pTexture->CreateFontTexture(rc.right, rc.bottom);
#endif // _TEXTURE_POWER_2
	}
	else
	{
		// 创建新纹理
		pTexture = new CFontTexture;

#ifdef _TEXTURE_POWER_2
		int texWidth = FONT_TEXTURE_WIDTH;
		int texHeight = FONT_TEXTURE_HEIGHT;
		if(rc.right>FONT_TEXTURE_WIDTH)
			texWidth = FONT_TEXTURE_WIDTH*2;
		if(rc.bottom>FONT_TEXTURE_HEIGHT)
			texHeight = FONT_TEXTURE_HEIGHT*2;
		pTexture->CreateFontTexture(texWidth, texHeight);
#else
		pTexture->CreateFontTexture(rc.right, rc.bottom);
#endif // _TEXTURE_POWER_2

		hFind = g_pTextureManager->InsertTexture(pTexture, MM_KEEPINMEMORY);
		m_FontTextureMap.insert(FontTextureValue(hFind, pTexture));
	}
	
	/*
		Write Sting & Output
	*/
	pTexture->WriteString(pString, m_hFont);
	::Render(hFind, x, y, NULL, color);
	pTexture->SetLastUseTime(dwNow);
}

//---------------------------------------------------
// 单行输出
//---------------------------------------------------
void GFont::DrawSingleLine(int x, int y, DWORD color, bool bCenter, const char *pString, ...)
{
	char szText[256];

	va_list va;
	va_start(va, pString);
	vsprintf(szText, pString, va);
	va_end(va);

	if(bCenter)
	{
		RECT rc = GetStringRect(szText);
		TextOut(x-rc.right/2, y-rc.bottom/2, color, szText);
	}
	else
	{
		TextOut(x, y, color, szText);
	}
}

//---------------------------------------------------
// 此值最好有判断是否大于纹理的最大长度
// 注意此值必须为偶数
//---------------------------------------------------
void GFont::SetLineCount(DWORD dwCount)
{
	/*
	int MaxCount = (FONT_TEXTURE_WIDTH/m_FontHeight)*2;
	if(dwCount>=MaxCount)
	{
		dwCount = MaxCount;
	}
	*/
	if(dwCount%2 && dwCount>=1)	
		dwCount = dwCount-1;
	m_LineCount = dwCount;
}

//---------------------------------------------------
// 获取字符串占用的RECT
//---------------------------------------------------
RECT GFont::GetStringRect(const char *pString)
{
	HDC	hDC			= CreateCompatibleDC(NULL);
	HFONT hOldFont	= (HFONT)::SelectObject(hDC, m_hFont);
	RECT rc = { 0, 0, 0, 0 };
	SIZE sz;
	::GetTextExtentPoint32(hDC, pString, strlen(pString), &sz);
	::SelectObject(hDC, hOldFont);
	::DeleteObject(hDC);

	rc.right = sz.cx;
	rc.bottom = sz.cy;

	return rc;
}

RECT GFont::GetStringRectMultiLine(const char *pString)
{
	RECT rc = { 0, 0, 0, 0 };
	const char *szBack = pString;
	if(pString==NULL || pString[0]==0)
	{
		return rc;
	}
	int TotalLen, CurLen, LeaveLen;
	int Ascii = 0, Chars = 0;
	char Tmp[256];
	int nLine = 0;
	TotalLen = strlen(pString);

	while(pString < szBack + TotalLen)
	{
		Ascii=0;
		Chars=0;
		memset(Tmp, 0, 256);

		LeaveLen = TotalLen - (int)(pString - szBack);
		if(LeaveLen > (int)m_LineCount) 
			CurLen = (int)m_LineCount;
		else 
			CurLen = LeaveLen;

		while((Chars < CurLen) && *pString)
		{
			//控制字符串处理

			Tmp[Chars] = *pString;
			pString++;
			Chars++;

			if((unsigned char)Tmp[Chars-1]<128)
				Ascii=1-Ascii;
		}
		// ASCII数量为单数
		if(Ascii==1 && pString < szBack + TotalLen)
		{
			pString--;
			Tmp[Chars-1]=0;
		}

		//_Show:
		nLine++;
		RECT temRc = GetStringRect(Tmp);
		if(temRc.right>rc.right)	rc.right = temRc.right;
		if(temRc.bottom>rc.bottom)	rc.bottom = temRc.bottom;
	}
	if(nLine>1)
	{
		rc.bottom = nLine*m_LineHeight-(m_LineHeight-rc.bottom);
	}

	return rc;
}

//---------------------------------------------------
// 更新
//---------------------------------------------------
void GFont::Update()
{
	DWORD tm = ::timeGetTime();
	if(tm - m_UpdateTime>FONTUPDATETIME)
	{
		FontTextureItor itor = m_FontTextureMap.begin();
		while(itor != m_FontTextureMap.end())
		{
			if((tm-(*itor).second->GetLastUseTime())>FONTMAXEXIST)
			{
				if(g_pTextureManager)
				{
					g_pTextureManager->DestroyTexture((*itor).first);
				}
				
				itor = m_FontTextureMap.erase(itor);
				continue;
			}
			itor++;
		}
		m_UpdateTime = tm;
	}
}

//--------------------------------------------------
/*

 Simple Font (2006_11_16)

*/
//--------------------------------------------------

CSimFont::CSimFont()
{
	m_hFont = NULL;
}

CSimFont::~CSimFont()
{
	if(m_hFont)
	{
		DeleteObject(m_hFont);
	}
	//不要自己删除,通过资源管理器删除
	//	m_pfTexture->Release();
	if(!g_pTextureManager)
	{
		return;
	}
	g_pTextureManager->ReleaseTexture(m_texHandle);
}

bool CSimFont::CreateFont(int nHeight, int nWidth, int nEscapement, int nOrientation, 
					   int fnWeight, DWORD fdwItalic, DWORD fdwUnderline, DWORD fdwStrikeOut,
					   DWORD fdwOutputPrecision, DWORD fdwClipPrecision, DWORD fdwQuality,
					   DWORD fdwPitchAndFamily, LPCTSTR lpszFace)
{
	if(m_hFont!=NULL)
	{
		DeleteObject(m_hFont);
	}

	m_hFont = ::CreateFont(nHeight, 
		nWidth, 
		nEscapement, 
		nOrientation, 
		fnWeight, 
		fdwItalic, 
		fdwUnderline, 
		fdwStrikeOut, 
		DEFAULT_CHARSET, 
		fdwOutputPrecision, 
		fdwClipPrecision, 
		fdwQuality, 
		fdwPitchAndFamily, 
		lpszFace);
	if(m_hFont==NULL)
	{
		WriteLog(INFO_ERROR, "Create font fail[%s]", lpszFace);
		return false;
	}

	m_pfTexture = new CFontTexture;
	m_texHandle = g_pTextureManager->InsertTexture(m_pfTexture, MM_KEEPINMEMORY);
	return true;
}

bool CSimFont::CreateFont(char * szFontName, DWORD height, DWORD width, DWORD weight)
{
	if(m_hFont!=NULL)
	{
		DeleteObject(m_hFont);
	}

	m_hFont = ::CreateFont(height, 
		width, 
		0, 
		0, 
		weight, 
		0, 
		FALSE, 
		FALSE, 
		DEFAULT_CHARSET, 
		OUT_DEFAULT_PRECIS, 
		CLIP_DEFAULT_PRECIS, 
		DEFAULT_QUALITY, 
		DEFAULT_PITCH|FF_SWISS, 
		szFontName);
	if(m_hFont==NULL)
	{
		WriteLog(INFO_ERROR, "Create font fail[%s]", szFontName);
		return false;
	}

	m_pfTexture = new CFontTexture;
	m_texHandle = g_pTextureManager->InsertTexture(m_pfTexture, MM_KEEPINMEMORY);
	return true;
}

void CSimFont::DrawText(int x, int y, DWORD color, bool bCenter, char * pString, ...)
{
	char szText[256];

	va_list va;
	va_start(va, pString);
	vsprintf(szText, pString, va);
	va_end(va);

	if(bCenter)
	{
		RECT rc = GetStringRect(szText);
		TextOut(x-rc.right/2, y-rc.bottom/2, color, szText);
	}
	else
	{
		TextOut(x, y, color, szText);
	}
}

RECT CSimFont::GetStringRect(char * pString)
{
	HDC	hDC			= CreateCompatibleDC(NULL);
	HFONT hOldFont	= (HFONT)::SelectObject(hDC, m_hFont);
	RECT rc = { 0, 0, 0, 0 };
	SIZE sz;
	::GetTextExtentPoint32(hDC, pString, strlen(pString), &sz);
	::SelectObject(hDC, hOldFont);
	::DeleteObject(hDC);

	rc.right = sz.cx;
	rc.bottom = sz.cy;

	return rc;
}

void CSimFont::TextOut(int x, int y, DWORD color, char * pString)
{
	if(pString[0]=='\0')
		return;
	if(m_pfTexture->Compare(pString))
	{
		::Render(m_texHandle, x, y, NULL, color);
	}
	else
	{
		m_pfTexture->Release();
		RECT rc = GetStringRect(pString);

#ifdef _TEXTURE_POWER_2
		int texWidth = FONT_TEXTURE_WIDTH;
		int texHeight = FONT_TEXTURE_HEIGHT;
		if(rc.right>FONT_TEXTURE_WIDTH)
			texWidth = FONT_TEXTURE_WIDTH*2;
		if(rc.bottom>FONT_TEXTURE_HEIGHT)
			texHeight = FONT_TEXTURE_HEIGHT*2;
		m_pfTexture->CreateFontTexture(texWidth, texHeight);
#else
		m_pfTexture->CreateFontTexture(rc.right, rc.bottom);
#endif // _TEXTURE_POWER_2
		m_pfTexture->WriteString(pString, m_hFont);

		::Render(m_texHandle, x, y, NULL, color);
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -