登录社区:用户名: 密码: 忘记密码 网页功能:加入收藏 设为首页 网站搜索  

文档

下载

图书

论坛

安全

源码

硬件

游戏
首页 信息 空间 VB VC Delphi Java Flash 补丁 控件 安全 黑客 电子书 笔记本 手机 MP3 杀毒 QQ群 产品库 分类信息 编程网站
  立华软件园 - 安全技术中心 - 技术文档 - 入门基础 技术文章 | 相关下载 | 电子图书 | 攻防录像 | 安全网站 | 在线论坛 | QQ群组 | 搜索   
 安全技术技术文档
  · 安全配制
  · 工具介绍
  · 黑客教学
  · 防火墙
  · 漏洞分析
  · 破解专题
  · 黑客编程
  · 入侵检测
 安全技术工具下载
  · 扫描工具
  · 攻击程序
  · 后门木马
  · 拒绝服务
  · 口令破解
  · 代理程序
  · 防火墙
  · 加密解密
  · 入侵检测
  · 攻防演示
 安全技术论坛
  · 安全配制
  · 工具介绍
  · 防火墙
  · 黑客入侵
  · 漏洞检测
  · 破解方法
 其他安全技术资源
  · 攻防演示动画
  · 电子图书
  · QQ群组讨论区
  · 其他网站资源
最新招聘信息

游戏编程起源(初学者)Ⅸ
发表日期:2007-01-17作者:[转贴] 出处:  

★ 第五章 DirectDraw的调色板和象素

☆ 简介

今天我们将分别使用调色板和RGB模式来熟悉DirectDraw的基本图形。它们有什么不同呢?如果你曾经在DOS下编程,你可能使用过调色板映射模式。调色板是个颜色查询表,为了绘制象素,你将一个单独的字节写入视频内存,通过这个字节你可以索引到一个拥有各种颜色的链表,这个颜色的链表,或查询表就叫作调色板。而RGB模式是不同的,因为它不需要颜色查询表。在RGB模式下绘制一个象素,你可以直接把红色、绿色和蓝色的值写入视频内存。任何色彩深度高于8位的调色板都可以用RGB模式取代。
编写本章时,我假设你已经读过了前面几章,知道了怎样设置DirectDraw和创建表面。我们将使用DirectX7,它包含了最新的DirectDraw接口。实际上,DirectX 7 中的DirectDraw接口可能是最后的升级版本了!不用担心,未来的版本一定会兼容它的,但是未来可能是一个DirectDraw和Direct3D综合的产品,管它那,我们学的不会没有用的。^_^
在开始前我还有最后一件事要提醒你:在我的后续文章中关于调色板的部分可能再也用不到了,所以,如果你对于调色板模式不是很感兴趣,你可以跳过文章的前一部分,从象素格式开始看起。调色板的开发和使用是PC中使用的原始视频系统的内存限制带来的直接后果。现在由于充足的显存使调色板模式几乎废弃不用了。值得保留调色板模式的一个原因是,执行调色板操作可以实现一些有趣的动画效果。不罗嗦了,让我们开始吧!

☆ 创建DirectDraw的调色板

当你在色彩深度为8位或低于8位的模式下显示图形时,你必须创建调色板,也就是颜色查询表。更明确的讲,对于DirectX,调色板就是PALETTEENTRY结构。要建立一个调色板,我们要做如下三步:
1、 创建颜色查询链表。
2、 得到指向IDirectDrawPalette接口的指针。
3、 把调色板链接到DirectDraw表面。

我假设我们使用的是8位色彩深度。如果你要用16位或更高位的色彩深度编写游戏,你就不用继续看以下这段疯狂的Windows素材了。总之,8位色彩深度,我们可以有一个256个条目的调色板。所以,创建颜色查询链表,有256个条目在其中:

typedef struct tagPALETTEENTRY { // pe
    BYTE peRed;
    BYTE peGreen;
    BYTE peBlue;
    BYTE peFlags;
} PALETTEENTRY;


头三个参数很明显,分别是红色、绿色和蓝色的强度。每一个取值范围0-255,BYTE是无符号数据类型。最后一个参数是控制标志,应该设置为PC_NOCOLLAPSE。原因我就不说了。
现在,我们需要把256个条目有秩序的排列好,也就是为了一下能找到,我们为链表设置一个数组,象这样:
PALETTEENTRY palette[256];
Ok,我们有了数组了,你可以装载颜色了。当我工作在调色板模式下时,通常把颜色存储在一个外部文件里,然后用一些如下的东东装载颜色:

FILE* file_ptr;
int x;

if ((file_ptr = fopen("palette.dat", "rb")) != NULL)
{
    fread(palette, sizeof(PALETTEENTRY), 256, file_ptr);
    fclose(file_ptr);
}

All right,第一步完成了。现在我们需要得到调色板的接口。交给IDirectDraw7::CreatePalette()函数就好了:

HRESULT CreatePalette(
    DWORD dwFlags,
    LPPALETTEENTRY lpColorTable,
    LPDIRECTDRAWPALETTE FAR *lplpDDPalette,
    IUnknown FAR *pUnkOuter
);

返回类型是HRESULT,你知道它的,所以可以用FAILED()和SUCCEEDED()这两个宏检测函数是否调用成功。参数的说明如下:
DWORD dwFlags:描述调色板对象的标志常量。当然,你可以用“|”组合它们:
◎ DDPCAPS_1BIT:1位色彩,对应2色调色板。
◎ DDPCAPS_2BIT:2位色彩,对应4色调色板。
◎ DDPCAPS_4BIT:4位色彩,对应16色调色板。
◎ DDPCAPS_8BIT:8为色彩,对应256色调色板。
◎ DDPCAPS_8BITENTRIES:指出引用一个8位色彩索引。就是说,每个颜色条目是它本身的到目的表面8位调色板的索引。这叫作被变址的调色板。它必须同DDPCAPS_1BIT、DDPCAPS_2BIT,或者DDPCAPS_4BIT合用。乱套吧!^_^
◎ DDPCAPS_ALPHA:每一个PALETTEENTRY的peFlags成员都应该被认为是阿尔发值。用这些标志创建的调色板可以被粘贴在Dierct3D纹理表面,因为DirectDraw本身并不支持阿尔发混合。
◎ DDPCAPS_ALLOW256:允许8位调色板的全部256个条目被使用。通常,0指向黑色,255指向白色。
◎ DDPCAPS_INITIALIZE:指出应该用PALETTEENTRY的数组初始化调色板。
◎ DDPCAPS_PRIMARYSURFACE:调色板将链接到主表面,好快速更改显示颜色。
◎ DDPCAPS_VSYNC:一般画圆时用到它。
大多数情况,你将使用DDPCAPS_8BIT | DDPCAPS_INITIALIZE,如果你刚好想建立一个空的调色板,稍后再设置它,你可以去掉后者,就是DDPCAPS_INITIALIZE。当然,你还可以使用DDPCAPS_ALLOW256,如果你真的想改变这两个常用的条目。
LPPALETTEENTRY lpColorTable:这个指针指向我们创建的查询表,把数组的名称传递给它就好了。
LPDIRECTDRAWPALETTE FAR *lplpDDPalette:这是指向IDirectDrawPalette接口指针的地址。如果函数调用成功,它将被初始化。
IUnkown FAR *pUnkOuter:同以前一样,这总是为COM高级应用准备的。设置为NULL好了。

不是太糟糕吧!现在我们可以建立我们的调色板对象了。最后一步是把调色板链接到一个表面,这只需要一个函数就好了——IDirectDrawSurface7::Setpalette()。它的原形如下:

HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette);

很简单,是不是?你只要把上一步得到的接口指针传递给它就可以了。那好,让我们把学到的综合到一起,下面我给你一个程序框架,我假设我们已经利用调色板的数组建立了一个索引链表,就像我们上一步做的。该框架是建立DirectDraw调色板来控制颜色,并且把它链接到主表面(当然,主表面是我们事先做好的):

LPDIRECTDRAWPALETTE lpddpal;

// create the palette object
if (FAILED(lpdd7->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE, palette, &lpddpal, NULL)))
{
    // error-handling code here
}

// attach to primary surface
if (FAILED(lpddsPrimary->SetPalette(lpddpal)))
{
    // error-handling code here
}

就是这么简单。一旦你的调色板建立完成,绘制象素部分同RGB模式就没有什么不同了。从此时开始,我将同时介绍RGB模式和调色板模式,在我们真正的显示图象前,我需要告诉你什么是RGB象素格式。

☆ 象素格式

象我前面说过的,当你把一个调色板模式的象素写入内存时,你同时分配了一个字节,每个字节表示一个到色彩查询表的索引。在RGB模式下,你只需要把颜色描述值写入内存,但每个颜色需要的字节数都要多于一个字节。字节的多少同色彩的深度相关。对于16-bit色彩,你要为每个象素准备两个字节(16位),以此类推,你可以猜到32-bit色彩是怎么回事了,这些都是很容易理解的。32-bit色彩对于一个象素来说,每一位的字符如下:

AAAA AAAA RRRR RRRR GGGG GGGG BBBB BBBB

“A”是代表“alpha”(阿尔发),表示一个透明的值,这是为Direct3D准备的。我以前说过,DirectDraw不支持α混合,所以当你为DirectDraw创建32-bit色彩时,把高位都设置为0好了。下一个8位表示红色强度的值,再下一个8位表示绿色,最后8位表示蓝色。
一个32-bit色彩的象素需要32位,所以我们一般用UINT类型来定义相对应的变量类型,这是一个无符号实数类型。通常我用一个宏来把RGB数据转换成正确的象素格式。让我给你看看它的样子,希望这能更好的帮助你理解象素格式:

#define RGB_32BIT(r, g, b) ((r << 16) | (g << 8) | (b))

就象你看到的,这个宏通过位移在相应的位置写入了相应的红、绿、蓝的强度值,并且完全符合正确的象素格式。是不是开始感觉有点儿入门了?要建立一个32-bit的象素,你就可以调用这个宏。红、绿、蓝每一个颜色的强度值都是8位,它们的取值范围都是从0——255。例如建立一个白色的象素,你可以这样:

UINT white_pixel = RGB_32BIT(255, 255, 255);

24-bit色彩基本相同,道理实际上是一样的,只是24-bit没有关于α的描述,也就是少了α那8位。象素格式如下:

RRRR RRRR GGGG GGGG BBBB BBBB

所以红色、绿色、蓝色仍然都分别是8位,这就意味着24-bit色彩和32-bit色彩实际上是有相同颜色深度的,只是32-bit多了个α混合。现在,你一定会想,24-bit比32-bit要好,真的是这样吗?否,因为使用24-bit有一些麻烦,事实上没有24-bit的数据类型,在你建立象素时,你不得不分三步写入红、绿、蓝的强度值,而不是象32-bit一次就完成。尽管32-bit色彩需要更多的内存,但在大多数的机器上,它要更快一些。实际上,很多显示卡不支持24-bit色彩模式,因为每一个象素占用3个字节是很不方便的。
现在,轮到16-bit色彩了,它有一点儿小麻烦,因为对于16-bit色彩,不是每一种显示卡都使用相同的象素格式!有两种格式。其中一种,也是比较流行的,红色占据5位,绿色占据6位,蓝色占据剩下的5位。另一种格式是分别都占据5位,剩下的一位,也就是高位不使用,一些老的显示卡都使用这种格式。所以这两种格式看起来是这样的:

565 format: RRRR RGGG GGGB BBBB
555 format: 0RRR RRGG GGGB BBBB

当你工作在16-bit色彩深度下,你首先需要检测显示卡是支持565格式还是555格式,然后使用适当的方式。这是很讨厌的,但你坚持用16-bit色彩,这是没有办法避免的。由于存在两种格式,你就需要两种宏:

#define RGB_16BIT565(r, g, b) ((r << 11) | (g << 5) | (b))
#define RGB_16BIT555(r, g, b) ((r << 10) | (g << 5) | (b))

对于565格式,红色和蓝色的取值范围是0——31,绿色是0——63;对于555格式,取值范围都是0——31,所以当要创建一个白色象素时,就会有所不同:

USHORT white_pixel_565 = RGB_16BIT565(31, 63, 31);
USHORT white_pixel_555 = RGB_15BIT555(31, 31, 31);

这个USHORT是无符号短实数类型,对应的变量只有16位。存在两种格式把事情搞得有些复杂,但在实际的游戏编程过程中,你将会感觉到这并没有你想象的那么讨厌。顺便说一下,有些时候555格式被称为15-bit色彩深度,所以在以后如果我这样谈到了它,你一定要心领神会哦!^_^
现在或许是告诉你在16-bit色彩深度模式下,怎样检测显示卡到底支持哪种格式的时机了,是555还是565呢?最简单的办法就是调用IDirectDrawSurface7接口下的GetPixelFormat()函数,它的原形如下:

HRESULT GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat);

参数是指向DDPIXELFORMAT结构的指针。你只要声明它,初始化它,然后传递它的地址就一切OK了。这个结构的本身是巨大的,所以我就不列举它了,但我得告诉你它的三个成员,都是DWORD类型的,它们是dwRBitMask、dwGBitMask、和dwBBitMask。你可以从dwRBitMask、dwGBitMask和dwBBitMask中获得掩码值(新东东,先不用太明白)。你也可以用它们检测显示卡支持的格式。如果显示卡支持565,dwGBitMask将为0x07E0。如果是555格式,dwGbitMask为0x03E0。
现在,我们已经学习了所有我们可能用到的象素格式,可以进入在DirectX下显示图象的实际阶段了。你已经等待了很久了,不是吗?在把象素放到表面上前,我们需要锁定表面,至少是锁定表面的一部分。锁定表面返回一个指向表面在内存里位置的指针,然后,我们就可以为所欲为了。

☆ 锁定表面

待续。。。。。。

我来说两句】 【发送给朋友】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 游戏编程起源(初学者)Ⅸ

 ■ [欢迎对本文发表评论]
用  户:  匿名发出:
您要为您所发的言论的后果负责,故请各位遵纪守法并注意语言文明。

最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放 / 友情链接  
Copyright ©2001-2006 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00208