|
|
发表于 2007-8-5 18:10:00
|
显示全部楼层
Re:关于人物头上显示名字的问题~~~~`
建议还是不要用这样的技术,用点投影到视锥平面的z=1的平面上,计算出xy坐标,直接写文字在上面效果就很好了,如果一定要做文字贴图可以用下面的方法,我过去做过深入的研究
#include ".\Cachedfonttexture.h"
#include "Colors.h"
CachedFontTexture::CachedFontTexture(int _fontsize,char *fontname, DWORD _dwBold, DWORD _dwItalic)
{
fontsize = _fontsize;
dwBold = _dwBold;
dwItalic = _dwItalic;
strcpy(m_strFontName, fontname);
LogOutable = false;
}
CachedFontTexture::~CachedFontTexture(void)
{
for ( p = FontTexMap.begin( ); p != FontTexMap.end( ); p++ ) {
if(LogOutable)
Logger: og(DEBUG_LV, "CachedFontexture:释放贴图...[%d]", p->first);
LPDIRECT3DTEXTURE9 _tex = ((PerFontTexCache)(p->second)).tex;
if(_tex)
_tex->Release();
}
//清除g_Guide
if( g_Guide != NULL )
{
g_Guide->Release();
g_Guide = NULL;
}// end if
}
//按该文字的asc码来查找文字贴图指针,如果找不到,返回0
LPPerFontTexCache CachedFontTexture::findFont(DWORD key) {
p = FontTexMap.find(key);
if(p == FontTexMap.end())
return 0;
else
return (LPPerFontTexCache)&p->second;
}
void CachedFontTexture::GetTexFromString(
IDirect3DDevice9* m_pd3dDevice,
LPDIRECT3DTEXTURE9 &_tex,
unsigned char* str,
int colnum, int rownum,
bool fixed, int colspan, int rowspan,
OUT int *texWidth, OUT int *texHeight
) {
//IDirect3DTexture9* _tex;
int _width = 0;
int _height = fontsize;
//////////////////////////////////////////////////////////////根据输入自动计算贴图的尺寸
if(fixed) { //固定行列
_width = (fontsize + colspan) * colnum;
_height = (fontsize + rowspan) * rownum;
} else { //计算一共是多少行多少列
int offsetx = 0;
size_t len = strlen((const char *)str);
for(size_t i = 0; i < len; i ++) {
unsigned char* p = &str;
if(str > 128) //表明当前一定是个汉字
{
if(offsetx > colnum * (fontsize + colspan) - fontsize) { //需要换行了
//g_Log.Log(DEBUG_LV, "%d...%d", offsetx, colnum * (fontsize + colspan) - fontsize);
_height += (fontsize+ rowspan);
offsetx = 0;
}
i++; //跳过另半个汉字
if(i<len-1)
offsetx+=(fontsize + colspan); //偏移中文的长度
} else { //不是个汉字
if(offsetx > colnum * (fontsize + colspan) - (fontsize>>1)) { //需要换行了
//g_Log.Log(DEBUG_LV, "%d...%d", offsetx, colnum * (fontsize + colspan) - (fontsize>>1));
_height += (fontsize+ rowspan);
offsetx = 0;
}
if(i<len-1)
offsetx+=((fontsize>> 1) + colspan); //偏移英文的长度+colspan
}
}
if(_height) { //表明换过行
_width = colnum *(fontsize + colspan);
} else {
_width = offsetx + fontsize;
}
}
if(texWidth) {
*texWidth = _width; //输出宽度
}
if(texHeight) {
*texHeight = _height; //输出高
}
if(_tex) {
_tex->Release();//上次创建过的先释放掉,再重新创建,否则会丢失内存了
}
////需要的width和height计算完毕,下面开始创建贴图了
HRESULT hr = m_pd3dDevice->CreateTexture( _width, _height, 1,
0, D3DFMT_A4R4G4B4,
D3DPOOL_MANAGED, &_tex, 0);
if(LogOutable)
Logger::Log(DEBUG_LV, "width:%d...height:%d", _width, _height);
int offsetx = 0;
int offsety = 0;
size_t len = strlen((const char *)str);
for(size_t i = 0; i < len; i ++) {
unsigned char* p = &str;
LPDIRECT3DTEXTURE9 tex=GetPerFontTex(m_pd3dDevice, p)->tex;
if(LogOutable)
Logger::Log(DEBUG_LV, "%d...%d", offsetx, offsety);
if(str > 128) //表明当前一定是个汉字
{
PasteTex(m_pd3dDevice, _tex, tex, offsetx, offsety,fontsize, fontsize);
i++; //跳过另半个汉字
offsetx+=(fontsize + colspan);
} else { //不是个汉字
PasteTex(m_pd3dDevice, _tex, tex, offsetx, offsety,fontsize>>1,fontsize);
offsetx+=((fontsize>>1) + colspan);
}
//下一个字是汉字或英文
if((str[i+1] > 128 && offsetx > _width - fontsize) || str[i+1] <= 128 && offsetx > _width - (fontsize >>1)) { //需要换行了
if(fixed && offsety + fontsize+ rowspan >= _height) { //固定行列要越界了,只能截断字符串了
break;
}
offsety += (fontsize+ rowspan);
offsetx = 0;
}
}
}
void CachedFontTexture: asteTex(IDirect3DDevice9* m_pd3dDevice,
LPDIRECT3DTEXTURE9 &destex,
LPDIRECT3DTEXTURE9 &srctex,
DWORD offsetx,
DWORD offsety,
int fwidth,
int fheight
) {
//static LPDIRECT3DTEXTURE9 _destex; //test
//if(!_destex) { //test
// HRESULT hr = m_pd3dDevice->CreateTexture( 32, 32, 1,
// 0, D3DFMT_A4R4G4B4,
// D3DPOOL_MANAGED, &_destex, 0);
//
// if(FAILED(hr)) {
// return;
// }
//}
D3DLOCKED_RECT destlockedRect;
D3DLOCKED_RECT srclockedRect;
destex->LockRect( 0, &destlockedRect, 0, 0 );
srctex->LockRect(0,&srclockedRect, 0, 0);
WORD* imageDataDest = (WORD*)destlockedRect.pBits; //D3DFMT_A4R4G4B4是16位色的,所以每个单位是WORD 2位
WORD* imageDataSrc = (WORD*)srclockedRect.pBits;
for(int i = 0;i < fheight; i ++) {
for(int j = 0; j < fwidth; j ++) {
int indexdest = (i+offsety) * destlockedRect.Pitch / 2 + (j + offsetx); //2位
int indexsrc = i * srclockedRect.Pitch / 2 + j;
imageDataDest[indexdest] = imageDataSrc[indexsrc];
}
}
srctex->UnlockRect(0);
destex->UnlockRect(0);
//destex = _destex;
}
LPPerFontTexCache CachedFontTexture::GetPerFontTex(
IDirect3DDevice9* m_pd3dDevice,
unsigned char* str
) {
unsigned char c1 = str[0];
unsigned char c2 = str[1];
DWORD key = 0;
if(c1 > 128) //说明是中文
key = MAKEWORD(c1, c2);
else //说明是英文
key = MAKEWORD(0, c1);
LPPerFontTexCache fp = findFont(key);
if(fp)
{
if(LogOutable)
Logger::Log(DEBUG_LV, "找到了贴图...[%d]", fp->texid);
//fp->usedtimes++; //使用次数自增
return fp; //找到了,返回该贴图的结构
}
LPDIRECT3DTEXTURE9 m_pTexture;
//找不到,创建一个贴图,然后添加到FontTexMap中去
PerFontTexCache texCache;
texCache.usedtimes = 0; //使用次数为0
if(c1 > 128)
texCache.isEN = false; //不是英文,是汉字
else
texCache.isEN = true; //是英文
DWORD m_dwTexWidth = fontsize;
if(texCache.isEN)
m_dwTexWidth = fontsize >> 1;
DWORD m_dwTexHeight = fontsize;
//DWORD m_dwFontFlags = dwFlags;
// Create a new texture for the font
HRESULT hr = m_pd3dDevice->CreateTexture( m_dwTexWidth, m_dwTexHeight, 1,
0, D3DFMT_A4R4G4B4,
D3DPOOL_MANAGED, &m_pTexture, 0);
if( FAILED(hr) )
return 0;
// Prepare to create a bitmap
DWORD* pBitmapBits;
BITMAPINFO bmi;
ZeroMemory( &bmi.bmiHeader, sizeof(BITMAPINFOHEADER) );
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = (int)m_dwTexWidth;
bmi.bmiHeader.biHeight = -(int)m_dwTexHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biBitCount = 32;
// Create a DC and a bitmap for the font
HDC hDC = CreateCompatibleDC( NULL );
DWORD size = 0;
HBITMAP hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
(void**)&pBitmapBits, NULL, size );
SetMapMode( hDC, MM_TEXT );
// Create a font. By specifying ANTIALIASED_QUALITY, we might get an
// antialiased font, but this is not guaranteed.
INT nHeight = fontsize;
//-MulDiv( m_dwFontHeight, (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 );
//DWORD dwBold = (m_dwFontFlags&D3DFONT_BOLD) ? FW_BOLD : FW_NORMAL;
//DWORD dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE : FALSE;
HFONT hFont = ::CreateFont( nHeight, 0, 0, 0, dwBold, dwItalic,
FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
VARIABLE_PITCH, m_strFontName );
if( NULL==hFont )
return 0;
SelectObject( hDC, hbmBitmap );
SelectObject( hDC, hFont );
// Set text properties
SetTextColor( hDC, RGB(255,255,255) );
SetBkColor( hDC, 0x00000000 );
SetTextAlign( hDC, TA_TOP );
ExtTextOut( hDC, 0, 0, ETO_OPAQUE, 0, (LPCSTR)str, 2, NULL );
D3DLOCKED_RECT d3dlr;
m_pTexture->LockRect( 0, &d3dlr, 0, 0 );
BYTE* pDstRow = (BYTE*)d3dlr.pBits;
WORD* pDst16;
BYTE bAlpha; // 4-bit measure of pixel intensity
for(int y=0; y < m_dwTexHeight; y++ )
{
pDst16 = (WORD*)pDstRow;
for(int x=0; x < m_dwTexWidth; x++ )
{
bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4);
if (bAlpha > 0)
{
*pDst16++ = (bAlpha << 12) | 0x0fff;
}
else
{
*pDst16++ = 0x0000;
}
}
pDstRow += d3dlr.Pitch;
}
// Done updating texture, so clean up used objects
m_pTexture->UnlockRect(0);
DeleteObject(hbmBitmap);
DeleteDC(hDC);
DeleteObject( hFont );
texCache.texid = key;
texCache.tex = m_pTexture; //把贴图保存到缓冲中去,下次还可以继续使用
FontTexMap.insert(tex_Pair(key, texCache));
if(LogOutable)
Logger::Log(DEBUG_LV, "创建了贴图...[%d]", key);
return &texCache;
}
void CachedFontTexture: rawSprite(IDirect3DDevice9* m_pd3dDevice,
LPDIRECT3DTEXTURE9 &m_pTexture,int x, int y, D3DCOLOR color)
{
if(!g_Guide) {
D3DXCreateSprite(m_pd3dDevice, &g_Guide); //还没创建过,那么创建一个好了
}
g_Guide->Begin( D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE );
g_Guide->Draw(m_pTexture, 0, 0, &D3DXVECTOR3(x, y, 0), color);
g_Guide->End();
}
//将指定的文本绘制到view投影平面上
void CachedFontTexture::DrawFontToScreen(
IDirect3DDevice9* m_pd3dDevice,
char *str ,int x, int y, int colnum, int rownum, D3DCOLOR color)
{
LPDIRECT3DTEXTURE9 __tex = 0;
GetTexFromString(m_pd3dDevice, __tex, (unsigned char *) str, colnum, rownum, false, 1, 1);
DrawSprite(m_pd3dDevice, __tex, x, y, color);
}
//将文字绘制到3D空间的某个位置,并投影到屏幕上,实现文字公告牌的效果
void CachedFontTexture::DrawFontToWorld(IDirect3DDevice9* m_pd3dDevice, char * str, float x, float y, float z,
int colnum, int rownum, D3DCOLOR color) {
D3DXVECTOR3 p(0.0f, 0.0f, 0.0f);
D3DXMATRIX worldMat;
D3DXMatrixIdentity(&worldMat);
worldMat._41 = x;
worldMat._42 = y;
worldMat._43 = z;
D3DXMATRIX viewMat;
D3DXMATRIX projectMat;
D3DVIEWPORT9 viewPortMat;
m_pd3dDevice->GetTransform(D3DTS_VIEW, &viewMat);
m_pd3dDevice->GetTransform(D3DTS_PROJECTION, &projectMat);
m_pd3dDevice->GetViewport(&viewPortMat);
D3DXVECTOR3 s;
//获取3D空间的P点投影到屏幕上的s点
D3DXVec3Project(&s, &p,
(D3DVIEWPORT9 *)&viewPortMat,
(const D3DXMATRIX*)&projectMat,
(const D3DXMATRIX*)&viewMat,
(const D3DXMATRIX*)&worldMat);
DrawFontToScreen(m_pd3dDevice, str, s.x, s.y, colnum, rownum, color);
}
|
|