??xml version="1.0" encoding="utf-8" standalone="yes"?> 另外QwxWidgets和Qt除了(jin)对于一些常见应用,比如H口、DC的封装之外,q提供了(jin)很多pȝ接口的封装,比如clipboard, thread, socket{?/p>
Qt有Qt Creator作ؓ(f)IDEQ工E项目文件可以跨q_Q另外,工程文g也可以用qmake转成q_无关的makefile。准备最q有I试QtQ个得商业代码质量还是要E微好一些?/p>
回复 更多评论
界面库名U?br>
接口设计
界面~辑?br>
高布局功能
q面l制
q_兼容?br>
语言支持
IDE兼容?br>
视图-模型分离机制
q行?br>
其它
Windows Forms
接口优秀。C++下用CLI扩展Q其它语a为原生支持?br>
界面~辑器完_(d)包括布局、属性、消息关联的完整讄。不可预览?br>
Table LayoutQSplitter LayoutQFlow Layout{,Anchor和Dock机制。多分L率界面下表现良好?br>
GDI+Q面向对象的2Dl制接口Q用简ѝ?br>
需?Netq_支持。WIndows或LinuxQMonoQ非官方支持Q,支持Windows CE
C++/CLI, 支持.net的语a?br>
仅VS?br>
布局和视图方案徏立在代码中。部分组件支持Model-View架构?br>
需要部|对应的.net
商业协议
MFC
Z宏和虚函敎ͼ使用Ҏ(gu)格式注释Q用自定义的RTTIpȝ。类接口设计优良。通过回调函数和虚l承重蝲调用客户代码?br>
Z资源~辑器,仅能对空间基本布局和少量属性进行调整。不可预览?br>
~Z高布局功能Q多分L率需要是手工或程序中调整?br>
GDI?qing)GDI装Q可选GDI+
WindowsQW(xu)indows CE
C++ OnlyQ?br>支持COM时可以实现BinaryU别复用?br>
仅Visual Studio
使用资源保存控g的基本控件布局Q提供Doc-View机制和控件数据交换支持视囑ֈR?br>
需要部|MFCq行时库?br>
商业协议
WTL
Z模板和虚函数。类接口cM于MFC。需要用多重(h)ѝ通过模板特化和回调函C客户代码交互?br>
同MFC
同MFC
同MFC
同MFC
同MFCQ对COM的支持比MFC完善很多?br>
Visual StudioQW(xu)indows下支持标准的C++~译器?br>
使用资源文g保存I间布局?br>
?br>
自由协议
wxWidget
宏,自定义RTTI。用回调函C用户代码交互?br>
无官方界面编辑器。可使用W三方界面编辑器。部分编辑器h完整的所见即所得功能,且具有预览能力?br>
使用Sizer实现多分辨率的布局。功能偏弱?br>
wxDC{?br>
WindowsQLinuxQUnixQMacOS{?br>
C++, .NET, Python,
Lua,
Ruby{?br>良好的编译器兼容性,~ZIDEl承?br>
可以界面属性生成到代码中,也可以用XML格式保存?br>
wx的动态链接库或静(rn)态链接?br>
自由协议
Qt
使用宏和自定义的RTTI。用Singal-Slot机制实现用户代码交互。可通过l承实现扩展?br>
Qt DesignerQ具备完整的所见即所得编辑功能。可预览界面?br>
具备完整的布局功能。多分L?多^C表现良好?br>
QCanvas{?br>
WindowsQLinuxQUnixQMacOS{?br>
C++QPython{?br>
可集成到Eclipse和VS
使用资源文g保存界面信息。部分组件具备Model-View-Delegate架构
qt的动态链接库?br>
开源协?商业协议
GTK+
使用signal-slot机制完成用户代码交互?br>
GLADEQ具备所见即所得的界面~辑功能
Layout ContainersQ具备较完整的布局能力?br>
GTK Graphics Context
WindowsQLinuxQUnixQMacOS{?/td>
CQC++QPythonQ?NET{?br>
Q暂时未知)(j)
使用代码完成界面讄。部分组件具备Model-View架构?br>
GTK Runtime
开源协?br>
# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方综合比?2009-01-06 19:05 qtopia
Nokia 最q推?Qt CreatorQ是较好的IDE环境 回复 更多评论
# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方综合比?2009-01-06 19:05 t
博主q可以增加一?#8220;国际化支?#8221; 回复 更多评论
# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方综合比较[未登录] 2009-01-08 12:48 kenlistian
我觉得wxwidget是不错的选择?nbsp; 回复 更多评论
# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方综合比?2009-01-11 20:25 www
wxwidget做简单的q可? 做复杂的界面,嘿嘿,那就ȝ(ch)? win下还是MFC最? 回复 更多评论
# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方综合比?2009-01-19 00:49 ArenAK
有没有哪一个是作者比较喜Ƣ用的呢Q及(qing)其原因? 回复 更多评论
# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方综合比较[未登录] 2009-01-19 16:35 六水
写的好~ 回复 更多评论
# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方综合比?2009-02-05 11:08 I明{
@六水
我就知道你是友情赞助的。。?nbsp; 回复 更多评论
# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方综合比较[未登录] 2009-02-11 22:35 六水
q你也知道? 回复 更多评论
# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方综合比?2009-02-25 10:19 aladdina
wxWidgets的代码质量不是很高,有一些比较初U的bug。我用过一D|间的wxWidgetsQ自己测试没问题Q但是用hM(x)发回一些crash report?/p>
# re: C++下Windows Forms + MFC + WTL + wxWidgets + Qt + GTK+ 非官方综合比?2009-09-18 12:09 idol
gtk 哪有 signal-slot机制Q用的明明是 callbacks 回复 更多评论
包括现在Q有很多游戏都还是用的炚w字库。因为操作v来比较方便,加上q方面的l验已经U篏?jin)好几年了(jin)。通常如果只是一U字体就可以满需要的话,它会(x)是一个比较好、快的解军_法。但是它?个缺?
1. 如果攑֤昄Q不做处理的话,昄出来的汉字,是很隄的?br>2. 像是UCDOS所提供的点阵字库,只有24炚w的有几种字体Q如Q宋(hu)体、黑体、揩?#8230;Q?6炚w的好象就只有?hu)体一U?br>3. 炚w字库Q通常是有版权的,其是第三方制作的汉字库Q如Q方正)(j)?br> 在这L(fng)情况下,当我们写好这L(fng)一个显C函敎ͼq是解决了(jin)如:(x)攑֤、快速显C等问题的话Q可供选择的字体还是太q于局限了(jin)。所以,在字体的要求比较强的情况下,炚w字库q不是一个好的解x(chng)法,他不够灵zR尽我们对于它的操作是如此得熟l,可以写出优美的代码来展示我们的编E技巧?/font>
TTF
TTF是True Type Font的简U。在Windows\Fonts目录下面Q我们可以看到许多后~为ttf的文Ӟ它就是接下来我们接下来所要谈到的?br> TTF是一U矢量字库。我们经常可以听到矢量这个词Q像是FLASH中的矢量囑ŞQ在100*100分L率下制作的flashQ就它攑֤为全屏,昄出的画面也不?x)出现马赛克。所谓矢量,其实说白?jin)就是用点和U来描述囑ŞQ这P在图形需要放大的时候,只要把所有这个图形的点和U放大相应的倍数可以了(jin)。而且Q在|站上有很多的TTF字库可以下蝲Q或者你可以M一些专门的字库光盘。然后在你发行你_ֿ(j)制作的游戏时Q可以顺便捎上这些后~?ttf 的文件就行了(jin)。包括Quakeq样的惊世之作,也都是用的TTF字库?br> q样Q我们就可以解决炚w汉字的一些问题。通过TTFQ我们在字体的质量和字库的数量上获得?jin)暂时性的胜利?/font>
字库的读取和昄
先前谈到炚w字库Q只需要很单的一些操作,可以显C出惌的汉字。下面我l出一个读取hzk16的函敎ͼ它需要一个Surface以供昄用:(x)
#include <io.h>
#include <stdio.h>
#include <conio.h>
// d16x16
void DispHZ16(int x, int y, BYTE *Str, LPDIRECTDRAWSURFACE surf)
{
const int Mask[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
FILE *HzkFp;
WORD i, j, k=0, m;
WORD HzNum;
WORD QuHao;
WORD WeiHao;
long offset;
BYTE dotBuffer[32];
HzkFp = fopen("HZK16", "rb");
HzNum = strlen((const char *)Str)/2;
DDSURFACEDESC ddsd;
LPWORD lpSurface;
HRESULT ddrval;
ddsd.dwSize = sizeof(ddsd);
while((ddrval=surf->Lock(NULL, &ddsd, 0, NULL))==DDERR_WASSTILLDRAWING);
if(ddrval == DD_OK)
lpSurface = (LPWORD)ddsd.lpSurface;
for(i = 0; i<HzNum; i++)
{
QuHao = Str[i*2]-160;
WeiHao = Str[i*2+1]-160;
offset = ((QuHao - 1) * 94 + (WeiHao-1))*32;
fseek(HzkFp, offset, SEEK_SET);
fread(dotBuffer, 32, 1, HzkFp);
for(j=0;j<16;j++)
for(k=0;k<2;k++)
for(m=0;m<8;m++)
if(dotBuffer[j*2+k] & Mask[m])
{
lpSurface[ddsd.lPitch*(y+j+1) + x+k*8+m] = 0x000000;
}
x+=16;
}
surf->Unlock(NULL);
fclose(HzkFp);
}
其实原理很简单:(x)
1. 打开字库
2. 计算字符串长度(q个函数只支持中文)(j)Qƈ且Lock Surface
3. 依次计算出每个汉字所对应的区码和位码Q汉字的W?个字节是区码Q第2个字节就是位码)(j)Q然后通过公式计算?gu)个汉字在字库中的偏移量?x)
offset = ((QuHao - 1) * 94 + (WeiHao-1))*32;
4. d一?2个字节的炚w
5. l制到Surface?br> 以上只是16Q?6炚w字库的显C方法,24Q?4的读取方法与之类|大家可以参照相关资料来书写出自己的代码?br>
如何昄TTF字库呢,有很多种手段Q下面我按从单到复杂的的序依次介绍:
1. 使用Windows APIQ也是大家所熟?zhn)的TextOut。通过它,q需要一个HDCQ设备句柄)(j)Q我们就可以随意地在屏幕M地方昄出文字了(jin)?br>2. 在http://www.freetype.orgQ有一个FreeType的免费库Q而且是OpenSource的。它目前?个版本:(x)1.0?2.0。其区别在于Q?.0只能dTTF格式的,?.0支持更多的文件格式,在用它之前误l阅L要遵循的LicenceQ以下是摘自 FreeType2.0对字库的支持列表Q?br>o TrueType fonts (and collections)
o Type 1 fonts
o CID-keyed Type 1 fonts
o CFF fonts
o OpenType fonts (both TrueType and CFF variants)
o SFNT-based bitmap fonts
o X11 PCF fonts
o Windows FNT fonts
3. 自己研究TTF的格式,然后自己来操作?br>?br>....... ╮╮
\?倒!
?br>虽然我们惌把每一件事情都做好Q但是也不是每一件事情都要亲历亲为。如果你非要q样Q也行^____^Q但是过不了(jin)多久Q你׃(x)陷入泥沼Q到时候你?x)发现自q热情正在慢慢被磨灭,什么叫做抓狂,怿你很快就?x)知道^_^?br>
在有多种选择可以取舍的情况下Q我们需要考虑一下,Ҏ(gu)一下各U解x(chng)法的优劣?br>
在DirectDraw时代Q我们都不自觉地喜欢上了(jin)GetDCQ因?#8230;…多方便啊。可是现在已l到?jin)DirectX8.1时代?jin)(我要使劲地摇那些q沉醉于DirectX7中,为如何在使用alpha时提升那可怜的1?个fps的朋友们Q醒醒,该v床了(jin)Q)(j)QHDC已经被M$列ؓ(f)用品。怎么办呢Q是的,你可能已l想C(jin)Q我们还?sh)直保存着H口的hWnd呢,可以通过它来得到hdcQ从而调用那些需要hdc的APIQ可是,q样做是更ؓ(f)愚蠢的,q样对你是没有一点好处的Q不信,你就试试吧。有一句话Q请牢记Q要想你的游戏有更快的速度的话Q请不要再去HDC?jin)?br> 我们非常清楚hdc是一个超慢的解决办法Q它无法在我们的高速游戏中?0分及(qing)根{下面来看看FreeTypeQ它更像是一个Service。它的解x(chng)法是Q先通过一pd的初始化和设|,告诉FreeType字体的名字和大小{,然后它会(x)动态地甌一个GraphicQ再把我们要昄的字dq个 Graphic上,你还可以把它保存?sh)tga格式。不q我们最l所惌的不是这个,所以可能我们还需要从q个Graphic上逐点d或者用 CopyRectQ然后再d我们的画面上。其实它已经是很方便的了(jin)Q可是需要你d?fn)如何配|和使用它,q是很花旉的一件事情,而且它最大的优点是可以跨q_Q我们需要它吗?如果有一个更为简单的办法Q像是如果Textout不是那么慢的话,好?#8230;…
在这里,Z谈一下另2个字体显C类QID3DXFont和CD3DFONT。可能早有Z(x)说怎么在上面的列表中没有它们?原因我会(x)在下面慢慢地说明Q?br> ID3DXFontQ它存在于D3DX库中Q一个现成的字体c,不过对于它的处理Ҏ(gu)……我实在不敢恭l_(d)引用一位大师所说的话来表达我的看法? 在内部实CQ?ID3DXFont::DrawText()函数实做了(jin)我上面讨论的工作Q先建立一张GDI兼容的位图,把文本绘制到位图上,而后把位图拷贝到U理贴图上去Q最后把U理渲染到屏q上。这样你p齐了(jin)所有的龟速的原始GDI函数Q还包括?jin)一大堆的额外开销 ?最l,q个函数比原来GDI的DrawTextEx()函数要慢上超q六?#8230;…
CD3DFONTQ是由M$在D3D的框架代码中提供。不q它只能昄英文Q有很多朋友通过自己定制和修改这个类Q来实现自己的中文显C。不q效果都不是很好。其实原理,跟ID3DXFont的方法差不多Q不q处理方法要聪明?jin)一炏V?/font>
分析与思?br> 那么我们应该怎么办呢Q通常我们?x)惻I如果可以像处理英文那P把所有的汉字都保存在一张位NQ该有多好。这P昄的速度׃是问题(sh)(jin)Q直接可以CopyRect上去。可是,q样可能吗?首先Q必L一U字体都要生成这L(fng)一个巨型位图。而且据说在GB2312中,一共有6000多个汉字Q就是?6*16Qoh my godQ这个位图该有多大啊Q据说会(x)?.5M^__^Q!Q!而且在DirectX8.1中,对于TextureQ显C的最单位,好象是原来 DirectSurface的概念一栗说q多遍?jin),不要再用DirectX8以前的东西了(jin)。不要试着d忆那些美好的q去Q我很明白,要你一下子攑ּ原来多年所获得的成,是一件很痛苦的事情,但是包袱太重Q是?x)?jing)响进步的。就像是我们的国?#8230;…扯远?jin)?j)Q不同的昑֍Q支持的最大容量也是不同的。比方说早期的VoodooQ只支持256*256大小的Texture。而在我的昑֍QGeforce2 MX 200Q上试Q支持最?048*2048大小的Texture。对于这L(fng)g不确定性,我们只能取其最|也就?56*256?br> 汉字虽然很多Q但是常用的汉字Q其实也只有那么几百个。像q样的字Q鬯、鞴Q你一辈子?x)看到多次呢?如果可以做一个类gCache的东西,保存着常用的那些个汉字Q在需要显C的的时候,先在Cache中查找,如果有的话,马上画上去Q如果没有,׃字库中提取到Cache中。这L(fng)话,在?Texture来保存汉字的位图信息的同Ӟ对于每个汉字Q我们还要定义一个结构,然后用一个东西把它串hQ综合它?个,也就实现?jin)我们所要的 Cache?jin)。刚开始,我所定义的结构是q样的:(x)
struct Char{
char hz[3]; // 保存汉字
int frequency;// 使用频率
RECT rect; // q个字对应位囄区域
Bool isUsing; // 是否使用
}
对于汉字和英文,我在q里大概地讲一下原理:(x)汉字是由2个字节保存,而英文只需?个。而判断一个字是否是汉字,只需判断W?个byte是否>128Q在原来的GB2312中,汉字?个字节都?gt;128的。而新的GBK字库Q汉字的W?个字节不一?gt;128Q我惌是扩大了(jin)字库定w的原因。我的意思是_(d)如果l一个字W串你,随机l其中一个位|,然后我问你这个位|是什么?你的回答只能是:(x)1 英文 2 汉字的首字节 3 汉字的尾字节。而这个问题的解法Qؓ(f)?jin)稳妥v见,你必M字符串的开始判断vQ。也是说在char[3]中,如果保存的是汉字Q则char[0]保存汉字W?个字节,char[1]保存汉字W?个字节,W?个存?#8217;\0’Q如果是英文的话Q则只用到char[0]Q其它的全部?#8217;\0’?br> 接下来,对于使用char[3]来保存汉字,是否真的很合适呢Q因为如果把它当作一个字W串来看的话Q在查找时就需要?strcmp 来比较字W串?jin),q样一定是?x)?jing)响速度的。如果不把它看作字符Ԍ字符串的最后一个字节需要以’\0’l尾Q,只用char[2]的话Q我们可以只是简单地调用宏MAKEWORDQ把2个byte压成1个WORD。当把文字作Z个WORD来看的时候,q样查找比较时可以用WORD内徏?=操作Q这栯比调用strcmp函数要快得多?br> int frequency用来标志每个WORD的用频率。设惻I如果一个字已经存在于Cache中,以后每对它调用一ơ,pfrequency++。这样做q有一个用意是Q是否可以在一个合适的时候,以frequency为参照来对这整个Cache排个序,把常用的字放在前面。那么在昄Ӟ可以先在 Cache中查找所要显C的字是否已l存在于Cache中,如果有则直接昄Q没有的话才需要采取某U手D将字加入到Cache中。一些常用的字(像:(x)我、的、着、了(jin)、过……Q,使得昄的速度会(x)大大提高?br> 其实上面说了(jin)半天的CacheQ它具体是什么呢Q其实就是指的最绘制单位,在DirectX7里是SurfaceQ而在DirectX8中就?Texture。用它来存放显C的汉字,q样Q就不用每次都从字库中读取或是调用如TextOutq类GDI慢的函C(jin)。因为每ơ在l制一个文字之前,都会(x)先在q个Cache中找Q有的话q接画上去Q没有才?x)调用TextOut操作。而这样做的原因,我们先设想一下:(x)游戏一般会(x)控制?0fps或是60fps的速度不停地刷斎ͼ如果在GameLoop中有M的代码是龟速的话Q这样就?x)导致fps的最大数的降低,也就意味着在保?0fps?60fps的同Ӟ能绘制到屏幕上的物体的数量减了(jin)。这是我们Z么要使用Texture来作为Cache的实现的原因。再一个,文字在屏q上昄时一般会(x)保持一D|_(d)q个旉可能?U?3U,我们的游戏也׃(x)相应地更?0fps?80fpsQ这是因Zh们需要阅d们。或者是一些如标题q样的文字,它们L不会(x)更新的,或是更新得很慢。我们完全可以在W一旉Q比方说我们的画面有60fpsQ在W?个fpsӞ我们得知要显C文?#8221;?#8221;Q然后先在Cache中找Q结果很p:(x)没有扑ֈQ这旉上用TextOut写到Texture上(现在q是属于W?个fps的时间范围内Q,而接下来?9?fpsQ甚x(chng)多)(j)Q都不用再调TextOut?jin),而是直接从我们的CacheQTexture上Copy到屏q上Q速度得到?jin)保障。谈到GDI的函敎ͼZ(jin)实现讑֤无关性,它们的速度都很慢。其实它们也不像说得那么慢,如果不是每一帧都要调用它们,也算是蛮快的^_^。那么这个RECT rectQ就代表着q个文字所对应在Texture上的区域位置?br> 使用什么东西来把这n个Char串v来呢Q一般会(x)惛_的是链表Q原因无非有2个:(x)1 随时有新的字加进来,而内存是不连l的 2 它几乎没有容量的限制Q除非是内存用完?jin)?j)。不q链表的讉K速度是很慢的Q如果用像数组q样的东西就好了(jin)。仔l想惻I在这里,我们用来存储?CacheQ最大也是256*256Q理׃面说?jin)?j)Q所以大应该会(x)是固定的。我们只需要在数组中的l每一个汉字加上一个标志,说明q个位置的用情c(din)那么就使用数组吧,q样的话Q访问的速度要更快一些,直接首地址+偏移量就够了(jin)Q不必像链表Q在查找旉要逐node讉K。当?dng)我绝不?x)惛_?new Char来申误个数l。因样做实在没有必要Q请不要q于q信自己的能力,在STL中已l有vector?jin),Z么还要自己写呢?^_^最后的一?bool成员变量isUsingQ也是上面所_(d)用来标志使用情况的?/font>
实际的操?br> 上面考虑?jin)那么多Q我认ؓ(f)都是实际操作之前所应该有的。先谈谈如何昄吧,因ؓ(f)在DirectX8.1中已l将DirectDraw?Direct3D融合为DirectGraphics?jin)。所以无法像原来那样?#8230;………哦,实在有太多东西要讲了(jin)Q我q是推荐几篇文章l你吧^_^Q?br> http://vip.6to23.com/mays/develop/directx/200201/Geczy3Din2D.htm
http://vip.6to23.com/mays/develop/directx/200201/GESurface.htm
http://vip.6to23.com/mays/develop/directx/200112/2DGtoDX8.htm
http://vip.6to23.com/mays/develop/directx/200201/DX8adv2D.htm
接下来,我会(x)假设你已l具备了(jin)在DirectX8.1中绘囄基本概念?jin),所以在你(h)l往(xin)下阅M前,请务必先仔细阅读以上推荐的文章?br> 前面提到Q需要一个vector来对应Texture上各个位|文字的信息Q上面已l创Z(jin)一个结构CharQ则q个vector的定义ؓ(f)Q?br> vector <Char> _vBuf; // 记录~冲中现有的文字情况
首先Q由于可以利用硬件的攑֤~小Q所以字体的大小_ֺ要求不是很高Q只需要支?6*16?4*24大小的字体就可以?jin)。我们需要一个这L(fng)初始化函敎ͼ(x)
bool CFont::
/*-------------------------------------------------------------
LPDIRECT3DDEVICE8 pd3dDevice --- D3DDevice讑֤
char szFontName[] --- 字体?? ?hu)?
int nSize --- 字体大小, 只支?6?4
int nLevel --- U理的大?br> -------------------------------------------------------------*/
Init( LPDIRECT3DDEVICE8 pd3dDevice, char szFontName[], int nSize, int nLevel )?br>
在DirectX8.1中,由SetTexture(…)所贴的囄大小Q也是Texture的大,是有大小限制的,长和宽都必须?^nQ而且位图大Q所p的显存越大,q样留给其他昄用的昑֭少?jin)。所以,必须Ҏ(gu)需求的不同Q来自定Texture(也就是Cache)的大。因为汉字点阵大的原因Q所以从实用角度而言Q比方说只是昄fps或是短小的标题)(j)Q开辟一?4*64大小的TextureQ才能满x(chng)低情况下的需要(q时如果选择16炚w的话可以存放16个汉字,24炚w可以存放7个,依次cL……Q?br> Ҏ(gu)讄Q创建TextureQ?br> _TextureSize = 32 << nLevel; // U理大小
_TextSize = nSize; // 文字大小
_TextureSize = 32 << nLevel; // U理大小
_RowNum = _TextureSize / _TextSize; // 计算一行可以容U_个文字
_Max = _RowNum * _RowNum; // 计算~冲最大?br>
创徏字体Q还是需要用Win32 API。也是先创Z个HDCQ?br> _hDc = CreateCompatibleDC(NULL);
然后创徏一个BITMAP和一个FONTQ将它们与HDC兌h?br> LOGFONT LogFont;
ZeroMemory( &LogFont, sizeof(LogFont) );
LogFont.lfHeight = -_TextSize;
LogFont.lfWidth = 0;
LogFont.lfEscapement = 0;
LogFont.lfOrientation = 0;
LogFont.lfWeight = FW_BOLD;
LogFont.lfItalic = FALSE;
LogFont.lfUnderline = FALSE;
LogFont.lfStrikeOut = FALSE;
LogFont.lfCharSet = DEFAULT_CHARSET;
LogFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
LogFont.lfQuality = DEFAULT_QUALITY;
LogFont.lfPitchAndFamily = DEFAULT_PITCH;
lstrcpy( LogFont.lfFaceName, szFontName );
_hFont = CreateFontIndirect( &LogFont );
if ( NULL == _hFont )
{
DeleteDC( _hDc );
return false;
}
Q只需要创Z个字体大的BITMAP卛_Q?br> BITMAPINFO bmi;
ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = _TextSize;
bmi.bmiHeader.biHeight = -_TextSize;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
Q这里需要定义一个指针指向位囄数据Q?br> DWORD * _pBits; // 位图的数据指针)(j)
_hBmp = CreateDIBSection( _hDc, &bmi, DIB_RGB_COLORS,
(void **) &_pBits, NULL, 0 );
if ( NULL == _hBmp || NULL == _pBits )
{
DeleteObject( _hFont );
DeleteDC( _hDc );
return false;
}
// hBmp和hFont加入到hDc
SelectObject( _hDc, _hBmp );
SelectObject( _hDc, _hFont );
接着讄背景色和文字Ԍ(x)
SetTextColor( _hDc, RGB(255,255,255) );
SetBkColor( _hDc, 0 );
讄文字Z寚wQ?br> SetTextAlign( _hDc, TA_TOP );
创徏Texture所需要的点~冲Q?br> if ( FAILED( _pd3dDevice->CreateVertexBuffer( _Max * 6 * sizeof(FONT2DVERTEX),
D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,
D3DPOOL_DEFAULT, &_pVB ) ) )
{
DeleteObject( _hFont );
DeleteObject( _hBmp );
DeleteDC( _hDc );
return false;
}
创徏Texture
if ( FAILED( _pd3dDevice->CreateTexture( _TextureSize, _TextureSize, 1, 0,
D3DFMT_A4R4G4B4, D3DPOOL_MANAGED, &_pTexture ) ) )
{
DeleteObject( _hFont );
DeleteObject( _hBmp );
DeleteDC( _hDc );
SAFE_RELEASE(_pVB);
return false;
}
讄渲染讑֤的渲染属性:(x)
_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, 0x08 );
_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
_pd3dDevice->SetTexture( 0, _pTexture );
_pd3dDevice->SetVertexShader( D3DFVF_FONT2DVERTEX );
_pd3dDevice->SetStreamSource( 0, _pVB, sizeof(FONT2DVERTEX) );
讄~冲的最大容?br> _vBuf.resize( _Max );
q样Q初始化完成?jin)。接下来是如何把一个汉字写到Texture中,以及(qing)如何q行理。定义函敎ͼ(x)
// 得到文字在纹理中的位|?br> void CFont::
/*-------------------------------------------------------------
char c1 --- 文字的第1个字?br> char c2 --- 文字的第2个字?br> int & tX --- 写入U理中的坐标x
int & tY --- 写入U理中的坐标y
-------------------------------------------------------------*/
Char2Texture( char c1, char c2, int & tX, int & tY )
{
WORD w = MAKEWORD(c1, c2); // 把此字变?sh)WORD
vector<Char>::iterator it = find( _vBuf.begin(), _vBuf.end(), w );
if ( it == _vBuf.end() ) // 如果没找?br> {
it = find( _vBuf.begin(), _vBuf.end(), 0 ); // 查找I闲位置
if ( it == _vBuf.end() ) // ~冲已满
{
for(; it!=_vBuf.begin(); it-- )
{
it->hz = 0;
}
// Log.Output( "字体~冲已满, 清空!" );
}
// 计算当前I闲的Char在缓冲中是第几个
int at = it-_vBuf.begin();
// 得到I闲位置的坐?br> tX = (at % _RowNum) * _TextSize;
tY = (at / _RowNum) * _TextSize;
// 讄q个CharZ用中
(*it).hz = w;
RECT rect = {0, 0, _TextSize, _TextSize};
char sz[3] = {c1, c2, '\0'};
// 填充背景为黑?透明?
FillRect( _hDc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH) );
// 往(xin)hBitmap上写?br> ::TextOut( _hDc, 0, 0, sz, c1 & 0x80 ? 2 : 1 );
// 锁定表面, 把汉字写入纹? 白色的是?可见), 黑色?透明)
D3DLOCKED_RECT d3dlr;
_pTexture->LockRect(0, &d3dlr, NULL, D3DLOCK_NOSYSLOCK);
BYTE * pDstRow = (BYTE*)( (WORD *)d3dlr.pBits + tY * _TextureSize + tX );
for (DWORD y=0; y<_TextSize; y++)
{
WORD * pDst16 = (WORD*)pDstRow;
for (DWORD x=0; x<_TextSize; x++)
{
BYTE bAlpha = (BYTE)((_pBits[_TextSize * y + x] & 0xff) >> 4);
if (bAlpha > 0)
*pDst16++ = (bAlpha << 12) | 0x0fff;
else
*pDst16++ = 0x0000;
}
pDstRow += d3dlr.Pitch;
}
_pTexture->UnlockRect( NULL );
}
else
{
// 计算当前I闲的Char在缓冲中是第几个
int at = it-_vBuf.begin();
// 得到q个字的坐标
tX = (at % _RowNum) * _TextSize;
tY = (at / _RowNum) * _TextSize;
}
}
以上代码中的注释已经很清楚了(jin)Q相信无L多言。这里唯一需要声明的是:(x)原来所定义的Charl构是这L(fng)
struct Char{
char hz[3]; // 保存汉字
int frequency;// 使用频率
RECT rect; // q个字对应位囄区域
Bool isUsing; // 是否使用
}
后来因ؓ(f)char hz[3]合成为WORDQ所以改为WORD hz。然后对于int frequencyQ这个词频应该如何表玎ͼ我一直没有想到很好的Ҏ(gu)。frequency应该在何?+呢?是在每次被用的时候吗Q但是这L(fng)话,上面说过Q游戏是?0fps的速度在刷斎ͼ如果停上1分钟的话Q变量很快就?x)溢Z(jin)。就是使用像是DWORD或__int64q样的巨型变量保存,也是不安全的。除非能在某个合适的时候将frequency清零Q但是这?#8220;时?#8221;是什么时候呢Q或者设|一个最大|?5535Q但是这样也基本上没什么用途,很快Q所有在vector中的Char中的frequency都会(x)++?5535的。回忆一下最初,是因为想把常用字攑ֈvector的前面,以便每次find操作可以最快返回结果的。而经q我的测试,即不做q样的优化操作,速度也是很快的,毕竟Cache不是很大Q加上vector是连l内存空间。所以可以放弃用int frequency?br> 然后对于RECT rectQ因为没有了(jin)int frequencyQ意味着一旦将汉字写入到TextureQ其位置׃?x)变动?jin)。所以,很容易根据find函数操作后的iteratorQ直接计出q个汉字所在Texture的位|。这PRECT rect也不再必R?br> 而bool isUsingQ它本n是个鸡肋,要也可以Q这L(fng)构更加清晰。不q,直接通过观察WORD hz?或非0Q即可实现isUsing的作用了(jin)?br> Z么要对结构Charq么_Nl琢呢?
1. 既然没有必要的东西,应该删?br>2. Charl构的大越大,vector所要求的内存越?br>3. 的l构Qfind可以更快地查扑և所l果
Z么find?x)正常工作呢Q这里我要大概地讲一下find是如何查扑և所需的位|的Q它只是单地使用while从vector的begin一直遍历到endQ逐个判断Q直到找Cؓ(f)止。find要求必须实现自己的operator ==()Q进一步跟t到find的源码中Q发C是这栗于是前面的l构Char变成?jin)现在这P(x)
struct Char{
WORD hz; // 文字
Char() : hz(0) {}
// 用作查找文字
inline bool operator == ( WORD h ) const
{
return hz==h ? true : false;
}
};
是不是很单?^___^
l于C(jin)昄的函C(jin)Q?br> // 得到文字在纹理中的位|?br> bool CFont::
/*-------------------------------------------------------------
char szText[] --- 昄的字W串
int x --- 屏幕坐标x
int y --- 屏幕坐标y
D3DCOLOR --- 颜色?qing)alpha?br> int nLen --- 字符串长?br> float fScale --- 攑֤比例
-------------------------------------------------------------*/
TextOut( char szText[], int x, int y, D3DCOLOR color, int nLen, float fScale )
{
Assert( szText!=NULL );
float sx = x, sy = y,
offset=0, w=0, h=0, tx1=0, ty1=0, tx2=0, ty2=0;
w = h = (float)_TextSize * fScale;
char ch[3] = {0,0,0};
FONT2DVERTEX * pVertices = NULL;
UINT wNumTriangles = 0;
_pVB->Lock(0, 0, (BYTE**)&pVertices, D3DLOCK_DISCARD);
if ( -1 == nLen || // 默认?1
nLen > lstrlen( szText ) ) // 如果nLen大于字符串实际长? 则nLen=实际长度
nLen = lstrlen( szText );
for (int n=0; n<nLen; n++ )
{
ch[0] = szText[n];
if ( ch[0]=='\n' )
{
sy+=h;
sx=x;
continue;
}
if ( ch[0] & 0x80 )
{
n++;
ch[1] = szText[n];
offset = w;
}
else
{
ch[1] = '\0';
offset = w / 2 ;
}
int a, b;
Char2Texture( ch[0], ch[1], a, b );
// 计算U理左上?0.0-1.0
tx1 = (float)(a) / _TextureSize;
ty1 = (float)(b) / _TextureSize;
// 计算U理右上?0.0-1.0
tx2 = tx1 + (float)_TextSize / _TextureSize;
ty2 = ty1 + (float)_TextSize / _TextureSize;
// 填充点~冲?br> *pVertices++ = FONT2DVERTEX(sx, sy + h, 0.9f, color, tx1, ty2);
*pVertices++ = FONT2DVERTEX(sx, sy, 0.9f, color, tx1, ty1);
*pVertices++ = FONT2DVERTEX(sx + w, sy + h, 0.9f, color, tx2, ty2);
*pVertices++ = FONT2DVERTEX(sx + w, sy, 0.9f, color, tx2, ty1);
*pVertices++ = FONT2DVERTEX(sx + w, sy + h, 0.9f, color, tx2, ty2);
*pVertices++ = FONT2DVERTEX(sx, sy, 0.9f, color, tx1, ty1);
wNumTriangles+=2;
sx+=offset; // 坐标x增量
}
_pVB->Unlock();
_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, wNumTriangles );
return true;
}
l束?br> 记得有一句名aQ?Keep it simple and stupid.在实现功能的同时Q保持代码简单、清晰是非常重要的一件事。相信在往(xin)后的日子里,在不论是别h阅读或是你自己回儡时候,你都?x)发C如既往(xin)地遵守这个守则,是多么得重要Q?br> 怿通过上面我那无数的废话,加上代码中还够的注释Q聪明的你一定能够明白这其中的原理了(jin)吧。如果以上的内容q(sh)以让你完全搞清楚的话,你可以登录我的主:(x)
炎龙工作?br> 上面不仅包括?jin)上面所写的E序代码Q还有一个用来演C效果的一个很单的demo?br> 说明Q以上所实现的CFont是包含在我的游戏引擎中的一个部Ӟ而目前已l实现的部g包括有:(x)
1. CGameFrameQ游戏框架类Q?----- 装?jin)窗口?qing)D3D讑֤的徏立,需要派生出自己的子c?br>2. CAudio和CSoundQ声音类Q?----- 支持wav/mid/mp3的播?br>3. CDirectInputQ控制类Q?----- 键盘、鼠标操?br>4. CDirectShowQ视频类Q?----- 支持avi/mpg/mov{的播放
5. CSpriteXQ精늱Q?----- 方便游戏中对_的控?br>6. CFontQ字体类Q?----- 中英文字体的昄
7. CTimerQ时间类Q?----- 高精度时间的控制
8. FPSQfps c)(j) ----- fps的计?br>9. LOGQ日志类Q?----- 游戏中的错误反应以及(qing)状态记?br> 最重要的是Q这个Game Engine完全是开放源代码的。关于更新的情况、版本说明以?qing)源码下载,请随时关注我的主?br>接下来,我将?x)?h)l完善这个EngineQ可能加入的有:(x)高效_子pȝ、斜45度角地图……
Ҏ(gu)如下Q引用)(j)Qhttp://blog.csdn.net/kun1234567/archive/2008/04/11/2282761.aspx
CEGUI使用utf8~码格式。这意味着我们可以很简单的显CZ文?/p>
1、弄个包含中文的字体Q在q里我借用大多C子里?“CQ?windows/Font/simhei.ttf”文g。把q个文g拯到Datafiles文g夹的Font文g多w?/p>
2、随便照着一?.Font文gQ自己写一个simhei.font文g。可以用TXT写,然后保存Q有的朋友说需要保存(sh)ؓ(f)utf8~码格式Q实际上是不需要的?/p>
3、同时注意修改你加蝲到程序里的scheme文gQ将里面的字体文件设|成simhei.ttf。你也可以(h)l用FirstWindowq个例子Q这L(fng)话直接修Ҏ(gu)代码里的字体为simhei.tff?/p>
4、现在在E序里进行字W编码{换,我拿代码说明问题Q?/p>
std::wstring aa = L"123中文abcあいうえ?;
char buff[128] = "";
WideCharToMultiByte( CP_UTF8, 0, aa.c_str(), aa.size(), buff, sizeof(buff), 0, 0);
button1->setText ( CEGUI::String ( CEGUI::utf8* )buff );
原理是这L(fng)Q对于utf8来说Q英文字W和ansi~码在内存布局上没什么区别,都是一个UCHAR。但是对于非英文字符Q则是UCHAR+UCHAR+UCHAR。如果我们手工进行编码格式{换,?x)比较?ch)琐?/p>
比较h的方法就是,我们先用WCHAR(unicode内存布局,UCHAR+UCHAR+UCHAR+UCHAR)来储存需要显C的字符Ԍ然后调用Win32API来帮我们把宽字符转换成char(多字节字W集内存布局)?/p>
q就是基本方法了(jin)Q然后我们可以根据这个{换方针,利用Win32API随意的{换字W编码格式,从而满程序中的各U需求?/p>
于是l箋(hu)Google(我很懒,别h能做的事情从来不ȝ(ch)自己Q懒得跟t代?Q结果还真让我找C(jin)两篇相关的文章:(x)一份是千里马肝的《游戏中汉字昄的实C技巧》,另一份是免费打工仔的《让OGRE支持中文》。从中找C(jin)原因Q?/p>
通过跟踪调试Q发C(jin)问题所在,原来|魁R是他:(x) const FontGlyph *Font::getGlyphData (utf32 codepoint) { } 原来CEGUIҎ(gu)Unicode字符的编码顺序,为每256个字W分配一张纹理(例如~码0-255存放在纹理一Q编?68-1023 存放在纹理四Q。英文很Ҏ(gu)搞定?jin),那么几个字符一张纹理就够了(jin)Q可中文得靠运气了(jin)Q有时显C几个字p生成几张U理Q还要将每张U理用不需要的盔R字填满,x(chng)伤胦(ch)Q?/p>
发现?jin)问题,我便按照千里马肝的思想对函数进行了(jin)攚w,用的文字攑օ一张纹理中Q因为纹理最大承?56个字Q所以,当汉字超q?56个时Q则不常用的去掉,新的字W写入?/p>
后来我发现汉字的引用没有太多的规律,常用的一千多汉字出现的概率没有那么?zhn)D(废话Q要不怎么是常用呢!Q,没有办法很好地按照用的频率汉字限制在256个字以内Q写q纹理,q(ch)性一旦满?jin)就字全部释放掉,重新写入。(也需有我没找刎ͼq请高手指教Q?/p>
代码如下Q?/p>
const FontGlyph *Font::getGlyphData (utf32 codepoint) { } void FreeTypeFont::rasterizeHZ (utf32 codepoint) { }
SOURCES +=main.cpp
CONFIG +=qt
ok 保存?/p>
打开命o(h)行,切换目录到hello.cpp所在目录。生成Makefile文gQ输入:(x)
qmake -o Makefile hello.pro Q?
接下来生成项目文?vcproj文g?
qmake -tp vc -o hello.vcproj hello.pro
3Q直接?span class=ColorResultsClass highlight="true" realoffset="1237" alpha-value="20">Qt Visual Studio Integration v1.2.2 for.VS.2003.2005插g(详见http://blog.csdn.net/znf19850924/archive/2008/01/16/2047373.aspx)
需要配|?span class=ColorResultsClass highlight="true" realoffset="1384" alpha-value="20">如下Q?/strong>
"Tools" -> "Options" -> "Qt" -> "Builds", d我们刚才~译?span class=ColorResultsClass highlight="true" realoffset="1405" alpha-value="20">Qt代码,名字?Qt 4.3.2", 路径?yourqtinstallpath)
启动一个新的工E?
选择"Qt projects" -> "Qt Application"cd,输入工程名字,单击OK.
双击工程文g里面?test.ui",马上出现?jin)所见及(qing)所得的H体~辑?在上面添加一个按?
双击按钮,产生相应的消息响应函?
d头文?
#include <QMessageBox>
在函数void Test::on_pushButton_clicked()体内d如下代码:
QMessageBox box(this);
box.setText("Haha, hit me.");
box.exec();