?? asl_font.cpp
字號:
//-----------------------------------------------------------------------------
//
// ____ Azure Star Game Engine 藍星游戲引擎 ____
//
// Copyright (c) 2006, 藍星工作室
// All rights reserved.
//
// 文件名稱: asl_font.cpp
// 摘 要: 字體類實現
//
// 當前版本: 1.0
// 作 者: 湯 祺
// 創建日期: 2006-8-6
//
//-----------------------------------------------------------------------------
#include "asl_font.h"
#include "asl_asm.h"
namespace ASL
{
//-----------------------------------------------------------------------------
// 函數名: ASLFont::ASLFont()
// 功 能: 構造函數
// 參 數: [void] - 無
// 返回值: [void] - 無
//-----------------------------------------------------------------------------
ASLFont::ASLFont(void)
: m_hDC(NULL)
, m_hBitmap(NULL)
, m_pCache(NULL)
, m_pCharBmpBuf(NULL)
, m_nCharBmpWidth(0)
, m_nCharBmpHeight(0)
, m_nSize(0)
, m_nAscent(0)
, m_nSpace(0)
, m_nTime(0)
, m_bSmooth(false)
{
}
//-----------------------------------------------------------------------------
// 函數名: ASLFont::ASLFont()
// 功 能: 構造函數
// 參 數: [font] - 要創建的字體
// [bSmooth] - 是否平滑字體
// [nCacheSize] - 緩存大小
// 返回值: [void] - 無
//-----------------------------------------------------------------------------
ASLFont::ASLFont(HFONT font, bool bSmooth, int nCacheSize)
{
Create(font, bSmooth, nCacheSize);
}
//-----------------------------------------------------------------------------
// 函數名: ASLFont::~ASLFont()
// 功 能: 析構函數
// 參 數: [void] - 無
// 返回值: [void] - 無
//-----------------------------------------------------------------------------
ASLFont::~ASLFont(void)
{
Destroy();
}
//-----------------------------------------------------------------------------
// 函數名: ASLFont::Destroy()
// 功 能: 銷毀字體
// 參 數: [void] - 無
// 返回值: [void] - 無
//-----------------------------------------------------------------------------
void ASLFont::Destroy(void)
{
SAFE_DELETE_ARRAY(m_pCache);
DeleteObject(m_hBitmap);
ReleaseDC(NULL, m_hDC);
m_hDC = NULL;
m_hBitmap = NULL;
m_pCharBmpBuf = NULL;
m_nCharBmpWidth = 0;
m_nCharBmpHeight = 0;
m_nSize = 0;
m_nAscent = 0;
m_nSpace = 0;
m_nTime = 0;
m_bSmooth = false;
}
//-----------------------------------------------------------------------------
// 函數名: ASLFont::Create()
// 功 能: 創建字體
// 參 數: [font] - 要創建的字體
// [bSmooth] - 是否平滑字體
// [nCacheSize] - 緩存大小
// 返回值: [void] - 無
//-----------------------------------------------------------------------------
void ASLFont::Create(HFONT font, bool bSmooth, int nCacheSize)
{
ASSERT(font != NULL && nCacheSize > 0);
// 若已創建過則銷毀重新創建
if (m_pCache != NULL)
{
Destroy();
}
m_bSmooth = bSmooth;
m_nSize = nCacheSize;
m_pCache = new CharInfo[m_nSize];
// 創建兼容DC并選入字體
m_hDC = CreateCompatibleDC(NULL);
SelectObject(m_hDC, font);
// 取字體數據
TEXTMETRIC tm;
GetTextMetrics(m_hDC, &tm);
m_nAscent = tm.tmAscent;
m_nCharBmpWidth = (tm.tmMaxCharWidth + 3) & ~3; // 字符位圖寬度
m_nCharBmpHeight = tm.tmHeight; // 字符位圖高度
m_nAveWidth = tm.tmAveCharWidth;
if (!m_bSmooth)
{
// 與字符位圖對應的BITMAPINFO結構
static int bmpinfo[13] = { sizeof(BITMAPINFOHEADER), 0, // 寬度 0, // 高度 0x100001, BI_BITFIELDS, 0, 0, 0, 0, 0, 0xf800, 0x7e0, 0x1f
};
bmpinfo[1] = m_nCharBmpWidth;
bmpinfo[2] = -m_nCharBmpHeight;
// 創建字符位圖
m_hBitmap = CreateDIBSection(m_hDC, (BITMAPINFO*)bmpinfo, DIB_RGB_COLORS,
(void**)&m_pCharBmpBuf, 0, 0);
SelectObject(m_hDC, m_hBitmap); // 將字符位圖選入DC
SetTextColor(m_hDC, RGB(255, 255, 255)); // 設文字顏色為白色 SetBkColor(m_hDC, RGB(0, 0, 0)); // 設背景顏色為黑色
}
}
//-----------------------------------------------------------------------------
// 函數名: ASLFont::DrawText()
// 功 能: 繪制字符串(格式化字符串)
// 參 數: [&bmDest] - 目標位圖
// [x] - 目標x坐標
// [y] - 目標y坐標
// [color] - 文字顏色
// [format] - 格式化字符串
// 返回值: [void] - 無
//-----------------------------------------------------------------------------
void ASLFont::DrawText(ASLBitmap &bmDest, int x, int y, COLOR color,
LPCSTR format, ...)
{
va_list va;
char str[256];
// 處理格式化字符串
va_start(va, format);
vsprintf(str, format, va);
va_end(va);
DrawText(bmDest, x, y, str, color);
}
//-----------------------------------------------------------------------------
// 函數名: ASLFont::DrawText()
// 功 能: 繪制字符串(普通字符串)
// 參 數: [&bmDest] - 目標位圖
// [x] - 目標x坐標
// [y] - 目標y坐標
// [str] - 字符串
// [color] - 文字顏色
// 返回值: [void] - 無
//-----------------------------------------------------------------------------
void ASLFont::DrawText(ASLBitmap &bmDest, int x, int y, LPCSTR str, COLOR color)
{
// 越界則直接返回
if ((x > bmDest.GetWidth()) || (y > bmDest.GetHeight()) || (str == NULL))
{
return;
}
UINT c1, c2;
int left = x;
// 依次處理每個字符,計算字符表示數
for (int i = 0; str[i] != '\0'; ++i)
{
c1 = (UCHAR)str[i];
// 若該字符為漢字
if (c1 > 0x80)
{
++i;
c2 = (UCHAR)str[i]; // 取漢字第二各編碼
if (c2 == 0) // 若字符串結束
{
break;
}
c1 = c1 * 256 + c2; // 計算漢字的字符表示數
}
const CharInfo &ci = _GetChar(c1); // 取該字符的信息
// 若該字符為可顯示字符則顯示之
if (c1 > 33)
{
_DrawChar(ci, bmDest, left, y, color);
}
left += ci.ciInc + m_nSpace; // 調整下一字符的繪制點
if (left > bmDest.GetWidth())
{
return;
}
}
}
//-----------------------------------------------------------------------------
// 函數名: ASLFont::DrawTextEx()
// 功 能: 自動分行繪制字符串
// 參 數: [&bmDest] - 目標位圖
// [x] - 目標x坐標
// [y] - 目標y坐標
// [str] - 字符串
// [color] - 文字顏色
// [length] - 每行字符數(以char為單位計數)
// [vspace] - 行距
// 返回值: [void] - 無
//-----------------------------------------------------------------------------
void ASLFont::DrawTextEx(ASLBitmap &bmDest, int x, int y, LPCSTR str, COLOR color,
int length, int vspace)
{
ASSERT(str != NULL);
char *buf = new char[strlen(str)];
strcpy(buf, str);
int iter = 0;
// 由于半角全角字可能混合存在, 需要逐字符處理
while (buf[iter] != '\0')
{
// 當前長度已大于等于指定長度, 需要繪制一行
if (iter >= length)
{
// 當前長度大于指定長度, 說明最后一個字是全角字
if (iter > length)
{
iter -= 2; // 退回一個全角字, 保證長度小于等于指定長度
}
// 給本行結尾加結束符, 并繪制這一行
char tmp = buf[iter];
buf[iter] = '\0';
DrawText(bmDest, x, y, color, buf);
buf += iter;
buf[0] = tmp;
iter = 0;
y += vspace;
continue;
}
if (buf[iter] < 0) // 全角字, 加2
{
iter += 2;
}
else // 半角字, 加1
{
iter++;
}
}
// 繪制最后一行
DrawText(bmDest, x, y, color, buf);
SAFE_DELETE_ARRAY(buf);
}
//-----------------------------------------------------------------------------
// 內部函數實現部分
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// 函數名: ASLFont::_GetChar()
// 功 能: 取字符信息
// 本函數使用LRU算法管理字符信息緩存,若緩存命中則直接從緩存中取字
// 符信息,若未命中則調用_SetChar()取字符信息覆蓋最久未使用的緩存塊
// 參 數: [ch] - 字符表示數
// 返回值: [const ASLFont::CharInfo&] - 字符信息
//-----------------------------------------------------------------------------
const ASLFont::CharInfo& ASLFont::_GetChar(UINT ch)
{
m_nTime++; // 計時器加1
// 計時器溢出則清零
if (m_nTime < 0)
{
m_nTime = 0;
for (int i = 0; i < m_nSize; ++i)
{
m_pCache[i].ciTime = 0;
}
}
// 在Cache中查找
for (int i = 0; i < m_nSize; ++i)
{
if (m_pCache[i].ciChar == ch) // Cache命中
{
m_pCache[i].ciTime = m_nTime; // 設該字符最后使用時間為當前時間
return m_pCache[i];
}
}
// Cache未命中,查找Cache中最久未被使用的字(ciTime最小)
int min = m_pCache[m_nSize-1].ciTime;
int pos = m_nSize-1;
for (int i = m_nSize-1; i >= 0; --i)
{
if (m_pCache[i].ciTime < min)
{
min = m_pCache[i].ciTime;
pos = i;
}
}
_SetChar(m_pCache[pos], ch); // 替換最久未被使用的字
m_pCache[pos].ciTime = m_nTime; // 設該字符最后使用時間為當前時間
return m_pCache[pos];
}
//-----------------------------------------------------------------------------
// 函數名: ASLFont::_SetChar()
// 功 能: 設置字符信息
// 參 數: [&ci] - 待填字符信息結構
// [ch] - 字符表示數
// 返回值: [void] - 無
//-----------------------------------------------------------------------------
void ASLFont::_SetChar(CharInfo &ci, UINT ch)
{
if (m_bSmooth)
{
int size; static MAT2 mat2={{0,1},{0,0},{0,0},{0,1}}; GLYPHMETRICS gm; // 取存放字符Alpha數據所需的緩沖區大小 size = GetGlyphOutline(m_hDC, ch, GGO_GRAY8_BITMAP, &gm, 0, NULL, &mat2); // 取緩沖區大小失敗,最可能原因為m_hDC中沒有選入字體 if (size <= 0) { //exception } // 申請緩沖區(存放字符Alpha數據) SAFE_DELETE_ARRAY(ci.ciData); ci.ciData = new BYTE[size]; // 取字符Alpha數據及其他輔助數據 if (GetGlyphOutline(m_hDC, ch, GGO_GRAY8_BITMAP, &gm, size, (LPVOID)ci.ciData, &mat2) == GDI_ERROR) { //exception }
// 填入其他字符信息
ci.ciChar = ch;
ci.ciWidth = gm.gmBlackBoxX;
ci.ciHeight = gm.gmBlackBoxY;
ci.ciPitch = (ci.ciWidth + 3) & 0xFFFFFFFC;
ci.ciOx = gm.gmptGlyphOrigin.x;
ci.ciOy = m_nAscent - gm.gmptGlyphOrigin.y;
ci.ciInc = gm.gmCellIncX;
}
else
{
static char str[3] = { 0, 0, 0 }; SIZE size;
// 將字符表示數轉換為字符串,輸出到內存中
if (ch < 256) { str[0] = (char)ch; str[1] = '\0'; ::TextOut(m_hDC, 0, 0, str, 1); ::GetTextExtentPoint(m_hDC, str, 1, &size); } else { str[0] = ch >> 8; str[1] = ch & 0xFF; ::TextOut(m_hDC, 0, 0, str, 2); ::GetTextExtentPoint(m_hDC, str, 2, &size); }
// 調整文字邊界,確保不出界
if (size.cx > m_nCharBmpWidth)
{
size.cx = m_nCharBmpWidth;
}
if (size.cy > m_nCharBmpHeight)
{
size.cy = m_nCharBmpHeight;
}
// 從內存中把16位數據轉為8位數據并保存到字符信息中
ci.ciData = new BYTE[size.cx * size.cy + 4]; // 加4是便于匯編處理
BYTE *pdst = ci.ciData;
WORD *psrc = (WORD*)m_pCharBmpBuf;
for (int i = 0; i < size.cy; ++i)
{
for (int j = 0; j < size.cx; ++j)
{
pdst[j] = psrc[j] == 0 ? 0 : 0xFF;
}
pdst += size.cx;
psrc += m_nCharBmpWidth;
}
// 填入其他字符信息
ci.ciChar = ch;
ci.ciWidth = size.cx;
ci.ciHeight = size.cy;
ci.ciPitch = size.cx;
ci.ciOx = 0;
ci.ciOy = 0;
ci.ciInc = size.cx;
}
}
//-----------------------------------------------------------------------------
// 函數名: ASLFont::_DrawChar()
// 功 能: 繪制字符
// 參 數: [&ci] - 字符信息
// [&bmDest] - 目標位圖
// [x] - 目標x點
// [y] - 目標y點
// [color] - 字符顏色
// 返回值: [void] - 無
//-----------------------------------------------------------------------------
void ASLFont::_DrawChar(const CharInfo &ci, ASLBitmap &bmDest, int x, int y,
COLOR color) const
{
ASSERT(ci.ciData != NULL);
RECT rect;
SetRect(&rect, 0, 0, ci.ciWidth, ci.ciHeight);
// 調整繪圖位置
x += ci.ciOx;
y += ci.ciOy;
if (x < 0)
{
rect.left -= x;
x = 0;
}
if (y < 0)
{
rect.top -= y;
y = 0;
}
if (x + ci.ciWidth > bmDest.GetWidth())
{
rect.right -= x + ci.ciWidth - bmDest.GetWidth();
}
if (y + ci.ciHeight > bmDest.GetHeight())
{
rect.bottom -= y + ci.ciHeight - bmDest.GetHeight();
}
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
// 若符合繪制條件
if (x < bmDest.GetWidth() && y < bmDest.GetHeight() && width > 0 && height > 0)
{
// 目的指針
BYTE *pdst = (BYTE*)bmDest.GetData() + y * bmDest.GetPitch() + x * 2;
// 字體數據通道指針
BYTE *psrc = ci.ciData + rect.top * ci.ciPitch + rect.left;
// 64位顏色值
__int64 clr64 = Bit16To64(color);
// 根據是否平滑繪制選擇不同的匯編函數
void (*DrawFunc)(BYTE*, BYTE*, int, __int64);
DrawFunc = m_bSmooth ? asmSmoothFont : asmPlainFont;
// 逐行處理
for (int i = 0; i < height; ++i)
{
DrawFunc(psrc, pdst, width, clr64);
psrc += ci.ciPitch;
pdst += bmDest.GetPitch();
}
}
}
} // namespace ASL
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -