编程初学者:游戏编程起源(初学者)Ⅸ



★ 第 5章 DirectDraw调色板和象素

☆ 介绍

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

☆ 创建DirectDraw调色板

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

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

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

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

FILE* file_ptr;
x;

((file_ptr = fopen(\"palette.dat\", \"rb\")) != NULL)
{
fread(palette, (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:每个PALETTEENTRYpeFlags成员都应该被认为是阿尔发值用这些标志创建调色板可以被粘贴在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
(FAILED(lpdd7->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE, palette, &lpddpal, NULL)))
{
// error-handling code here
}

// attach to primary surface
(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数据转换成正确象素格式让我给你看看它样子希望这能更好帮助你理解象素格式:

# 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数据类型在你建立象素时你不得不分 3步写入红、绿、蓝强度值而不是象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色彩这是没有办法避免由于存在两种格式你就需要两种宏:

# RGB_16BIT565(r, g, b) ((r << 11) | (g << 5) | (b))
# 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了这个结构本身是巨大所以我就不列举它了但我得告诉你它 3个成员都是DWORD类型它们是dwRBitMask、dwGBitMask、和dwBBitMask你可以从dwRBitMask、dwGBitMask和dwBBitMask中获得掩码值(新东东先不用太明白)你也可以用它们检测显示卡支持格式如果显示卡支持565dwGBitMask将为0x07E0如果是555格式dwGbitMask为0x03E0
现在我们已经学习了所有我们可能用到象素格式可以进入在DirectX下显示图象实际阶段了你已经等待了很久了不是吗?在把象素放到表面上前我们需要锁定表面至少是锁定表面部分锁定表面返回个指向表面在内存里位置指针然后我们就可以为所欲为了

☆ 锁定表面

待续

Tags:  网络游戏的起源 网络游戏起源 游戏的起源 编程初学者

延伸阅读

最新评论

发表评论