分享
 
 
 

游戏开发新手入门之位图化图形

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

简介

终于,你已经掌握了制作一个完整游戏的基础知识了,只不过你现在还只能使用GDI。今天,我们就学习使用DirectX来执行每一件你以前用GDI完成的工作,以及一些关于DirectX其它的东东。具体内容是:装载(调用)位图,使用位块传输,填充表面,使用剪裁板、颜色键等拷贝位图。

你可以在不了解前一章内容的基础上学习本章,但象素格式是很重要的,我将经常直接或间接的提到它,所以你至少应该看看上一章关于象素格式的部分!另外,我假设你已经本系列的第一、二、三、四章,并且拥有一个DirectX SDK游戏开发平台。准备好了吗?发动引擎吧,女士们、先生们!

装载位图

不管你信不信,你的确已经知道了把位图装载到DirectDraw表面的大部分知识。怎么会这样呢?Well,在Windows GDI下装载位图同在DirectDraw下极其相似,只是有一点点不同。轻轻的回忆一下,我们曾经使用LoadImage()函数得到位图的句柄,然后把位图选入到内存设备上下文中,最后利用BitBlt()函数把图形从内存设备上下文中拷贝到显示设备上下文中,设备上下文可以用GetDC()函数得到。如果这个承担显示任务的就是DirectDraw表面(现在我们就是要用它),我们就可以针对性的得到DirectDraw表面的设备上下文!感谢上帝,IDirectDrawSurface7接口提供了一个极其简单的函数来得到这个设备上下文:

HRESULT GetDC(HDC FAR *lphDC);

该函数的返回类型同所有DirectDraw函数的返回类型相同。如果函数调用成功,参数就是一个HDC类型的设备上下文的指针,很简单吧!本章就是从把一个位图装载到DirectDraw表面讲起的。千万要记住使用完了表面设备上下文后,你一定要释放它哦!你可能已经想到了,用表面接口函数ReleaseDC()完成:

HRESULT ReleaseDC(HDC hDC);

你不用回头去看关于GDI部分的位图调用,我将把适合于DirectDraw的位图调用展现给你。唯一不同的是:不是直接把设备上下文作为一个参数,而是用一个DirectDraw表面指针取代了它,然后函数从表面得到设备上下文,用它来拷贝图形,最终释放设备上下文。(可能这里我说的有些混乱,但你看一下下面的程序代码就都明白了):

int LoadBitmapResource(LPDIRECTDRAWSURFACE7 lpdds, int xDest, int yDest, int nResID)

{

HDC hSrcDC; // source DC - memory device context

HDC hDestDC; // destination DC - surface device context

HBITMAP hbitmap; // handle to the bitmap resource

BITMAP bmp; // structure for bitmap info

int nHeight, nWidth; // bitmap dimensions

// first load the bitmap resource

if ((hbitmap = (HBITMAP)LoadImage(hinstance, MAKEINTRESOURCE(nResID), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION)) == NULL)

return(FALSE);

// create a DC for the bitmap to use

if ((hSrcDC = CreateCompatibleDC(NULL)) == NULL)

return(FALSE);

// select the bitmap into the DC

if (SelectObject(hSrcDC, hbitmap) == NULL)

{

DeleteDC(hSrcDC);

return(FALSE);

}

// get image dimensions

if (GetObject(hbitmap, sizeof(BITMAP), &bmp) == 0)

{

DeleteDC(hSrcDC);

return(FALSE);

}

nWidth = bmp.bmWidth;

nHeight = bmp.bmHeight;

// retrieve surface DC

if (FAILED(lpdds-GetDC(&hDestDC)))

{

DeleteDC(hSrcDC);

return(FALSE);

}

// copy image from one DC to the other

if (BitBlt(hDestDC, xDest, yDest, nWidth, nHeight, hSrcDC, 0, 0, SRCCOPY) == NULL)

{

lpdds-ReleaseDC(hDestDC);

DeleteDC(hSrcDC);

return(FALSE);

}

// kill the device contexts

lpdds-ReleaseDC(hDestDC);

DeleteDC(hSrcDC);

// return success

return(TRUE);

}

上面这段代码被设计成从资源调用位图,但你可以很容易就把它修改成从外部文件调用位图,或者更理想的是,首先你从资源调用位图,如果失败,再试图从外部文件调用位图。从外部调用,需要记住的是调用LoadImage()函数时加上LR_LOADFROMFILE标志。最美妙的事情是,函数BitBlt()自动完成象素格式的转换。举例说,当我们把24-bit的位图放入内存设备上下文,再把它传送(拷贝)到16-bit色彩深度的表面,所有的颜色将得到正确的显示,不用顾忌象素格式是555还是565,很方便吧,哦?

如果你要控制位图传递的实际过程,而不是使用BitBlt()这样简单的函数,你有两个选择。第一个,你可以修改这个函数,需要利用BITMAP结构的bmBits成员,它是一个组成图象的位的LPVOID指针变量。第二种方法,如果你真的想控制图象的调用过程,你可以自己编写函数,思路是使用标准的I/O函数来打开图象文件,然后读取它。要这样做,你需要了解位图文件的结构。我们将不涉及这种函数的编写,因为目前的对我们来说已经足够了,但我还是要为你将来的大展鸿图做一点点铺垫。

位图格式

令人高兴的是,要自己写一个调用位图的函数,有一个Win32结构的位图头文件可以利用。读取这个头文件的信息,用fread()这样简单的函数就可以了。所有的位图文件都有这样一个头文件,它包含了位图的全部信息。BITMAPFILEHEADER就是这个头文件结构的名字,下面是它的原形:

typedef struct tagBITMAPFILEHEADER { // bmfh

WORD bfType; // file type - must be "BM" for bitmap

DWORD bfSize; // size in bytes of the bitmap file

WORD bfReserved1; // must be zero

WORD bfReserved2; // must be zero

DWORD bfOffBits; // offset in bytes from the BITMAPFILEHEADER

// structure to the bitmap bits

} BITMAPFILEHEADER;

我就不详细介绍这些成员了,因为注释里已经说得很清楚了,只要使用fread()读取它们就可以了。注意要检测bfType成员是否等于字符“BM”,若是,说明你正在处理一个有效的位图。在此之后,有另一个头文件需要读取,它包含位图的尺寸、压缩类型等图象信息。以下是它的结构:

typedef struct tagBITMAPINFOHEADER{ // bmih

DWORD biSize; // number of bytes required by the structure

LONG biWidth; // width of the image in pixels

LONG biHeight; // height of the image in pixels

WORD biPlanes; // number of planes for target device - must be 1

WORD biBitCount; // bits per pixel - 1, 4, 8, 16, 24, or 32

DWORD biCompression; // type of compression - BI_RGB for uncompressed

DWORD biSizeImage; // size in bytes of the image

LONG biXPelsPerMeter; // horizontal resolution in pixels per meter

LONG biYPelsPerMeter; // vertical resolution in pixels per meter

DWORD biClrUsed; // number of colors used

DWORD biClrImportant; // number of colors that are important

} BITMAPINFOHEADER;

只有几个成员需要解说一下。第一个,注意压缩格式。大多数的位图你都需要做解压缩的操作。最普通的位图压缩格式是run-length编码(RLE),但只能应用于4-bit或8-bit图象,在此情况时,成员biCompression将分别是BI_RLE4和BI_RLE8,我们就不讨论这种压缩格式了,但它真的很简单,很容易理解,你如果要了解它是不会有任何麻烦的。

第二个,对于高色彩的位图,biClrUsed和biClrImportant这两个成员通常设置为0,所以不用太在意它们。对于BI_RGB这种未压缩格式的位图,成员biSizeImage也将被设置为0。最后,针对我们的目的,其它的结构成员都不是很重要的,我们只需要注意位图的长、宽和色彩的深度(biWidth、biHeight、biBitCount)。

读取完了这些头文件的信息后,如果位图是8-bit或者以下色彩深度的(也就是调色板模式),调色板的信息会紧跟在这些信息之后。也许出乎你的意料,调色板的信息不是存储在PALETTEENTRY结构中,而是在RGBQUAD结构中。RGBQUAD结构如下:

typedef struct tagRGBQUAD { // rgbq

BYTE rgbBlue;

BYTE rgbGreen;

BYTE rgbRed;

BYTE rgbReserved;

} RGBQUAD;

不要问我为什么红、绿、蓝以倒序方式排列,事实就是这样!读取RGBQUAD中的数据,把数据传递给DirectDraw调色板的数组。记得要把每个PALETTEENTRY的peFlag设置成PC_NOCOLLAPSE。

之后呢(调色板信息不一定存在,因为高彩模式下就没有),你将发现图象位(image bits),你可能会想到建立一个指针,在内存中分配足够的空间来控制这些图象位数据,然后读取它们。对极了,我正要这样干。假设把存储在BITMAPINFOHEADER结构中的信息头文件称作info,你的图象位指针称作fptr,实施的代码如下:

UCHAR* buffer = (UCHAR*)malloc(info.biSizeImage);

fread(buffer, sizeof(UCHAR), info.biSizeImage, fptr);

要记住,在一些情况下,biSizeImage的值可能为0,所以有必要在上面的代码运行前检测它一下。如果它被设置为0,你将不得不计算图象由多少个象素构成,每个象素需要多少个字节。

写你自己的位图调用函数,并

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有