DirectX
DirectX是由微软开发的一组API(应用程序编程接口),旨在为Windows应用程序提供高性能的音频、视频和游戏功能。
通过硬件抽象层(HAL)和硬件仿真层(HEL)来保证设备无关性和让你的程序正常运行。
DirectDraw
DirectDraw 主要用于2D图形加速,而DirectX还包括Direct3D(用于3D图形渲染)、DirectSound(音频处理)、DirectInput(游戏设备输入)等。
DirectDraw 是 Microsoft DirectX 的显示组件,使软件设计人员能够直接操作显示内存、硬件分片、硬件覆盖和翻转图面。 提供对直接 32 位路径中特定于设备的显示功能的独立于设备的访问权限,直接访问显示卡的驱动程序中调用重要函数,而无需 Windows 图形设备接口 (GDI) 或与设备无关的位图 (DIB) 引擎。
DirectDraw提供了与硬件无关性的同时允许直接操作显存。与Windows 图形系统接口(GDI)相兼容,可直接操作显示设备,是DirectX技术中进行图像处理的基础,是DirectX中的关于视频输入输出的基本部分,只要使用的硬件支持DirectDraw,开发人员就可以使用DirectDraw可以方便地编制出高效的视频处理、图像处理的程序来。
COM
部件对象模型(Component Object Model, COM)是OLE 的基础。COM 为OLE提供了编程模型和二进制标准。COM定义并实现了软部件(如应用程序、数据对象、控件及服务)机制,并把它们统称为“对象”。每个软部件对象由数据以及访问数据的函数组成,访问软部件对象数据的函数的集合称为“接口”。
所有的COM接口都是从Iunknown接口继承而来的,IUnknown接口是所有COM接口的根。IUnknown接口具有3个方法:
- QueryInterface():此方法查询新接口,并在新接口存在时返回之。
- AddRef():此方法在接口或其它应用程序连编到此COM对象上时将引用计数值递加1。
- Release():此方法将COM对象的引用计数递减1。当引用计数递减到0时,该COM对象自动释放。
DirectX是基于COM的一套软件编程接口。
色彩
采用标准的24位RGB模式定义一个颜色(3字节,分别代表红,绿,蓝三基色的颜色、值,从0到255)。
绘图基础
设备无关位图(DIB)
Windows中,当然还包括DirectX,都使用设备无关位图DIB(Device-Independent Bitmap)作为其最基本的图象文件格式。在大多数情况下,我们将其简称为位图(Bitmap)。
DIB是一个包含了图象的各种信息的文件,包括图象的尺寸,使用的颜色个数及其颜色值,还有每个像素的颜色数据等。
位深度(Bit depth)
通常用位深度来代表位图中的颜色值所使用的位个数(有多少种颜色)。
1字节能且最多只能反映出256( 2 8 2^8 28)种不同的状态。在位图中,如果用其中每一种状态代表图象中某一个点的颜色,那么最多可以得到256种不同的颜色,这就是我们常见的8位(256色)的位图。
DirectDraw采用24位RGB模式,16M( 2 2 4 2^24 224)种颜色。24位,即3字节,分别代表红,绿,蓝三基色的颜色、值,从0到255。
调色板(Palette)
显示器及显示卡与显示器的接口都采用模拟方式来处理色彩,因此,它们都具有几乎无限的色彩显示和传输能力。但主机和显示卡只能用数字方式来表示和处理色彩,如果要获得更丰富,更细腻的色彩就需要增加色彩的位深度,这就需要更大容量的显示存储器、更高的处理速度,同时分辨率的提高也对显示存储器的容量提出了很高的要求。
调色板(Palette)表示法:一种间接的色彩表示方法,降低对显存的需求。用一个颜色索引(Color Index)来代表各个像素点的颜色。色彩表(调色板)是一个包含了若干颜色索引和该索引所对应的真实颜色值的表。
在16色模式下显示一幅256色或更高位深度的的图象时,本应色彩鲜艳的图片变得面目全飞。原因:同时显示在屏幕上的不同颜色最多只能有16种,于是Windows首先从图象中挑选了16种使用频率最高的颜色指定给调色板。对于所有其它的颜色,从调色板中挑选一个最接近的颜色显示出来。
图形设备接口GDI(Graphics device interface)
GDI不是为具有高表现力的多媒体软件和游戏而设计的。只提供了访问系统主存的能力,而不提供直接访问显存的能力,并不能从具有某些加速特性的显卡中获得其优良特性。
DirectDraw可以提供给开发者代表了真实显示内存的绘图页面。可以直接操纵显卡上的内存,图形显示变得出奇的快速。而且这些页面代表了显存中连续的内存块,使得在页面中寻址和读写变得非常方便。
位块传送(Blit,Bit block transfer)
将某一内存块的数据传送(变换转移,不是复制)到另一内存块。
光栅操作代码(ROP,Raster operation code):变换方式。
IDirectDrawSurface3::Blt可以利用硬件加速特性,可异步执行的,不需要等待blit结束才返回,然后系统在后台进行blit操作;还支持带源和目标关键色以及z缓存和alpha 通道的blit操作,完成各种效果变得极更为容易。
关键色(Color Key)
DirectDraw的blit函数,支持带关键色(Color key)的透明blit操作。如果在源页面上指定了一个颜色为关键色,那么在blit操作中,将视具有这种颜色的区域为透明,不会被传送到目标页面上。矩形区域中只有属于精灵的像素被映射了,其余带关键色的像素全被视为透明,对目标页面不会产生任何影响。
在包含精灵图像(不规则形状)的矩形内,将不属于精灵图像的部分全部使用同一种颜色,或使其在一个颜色范围之内(关键色,精灵图像中所没有用到的)。
源关键色(Source color key):在Blit过程中,不被复制;或在覆盖页面中,对目标层来说是不可见的。
目标关键色(Destination color key)在Blit过程中,将被替换;在覆盖页面中,将被目标层所覆盖。
视频RAM读写
如果你的应用程序要写视频RAM,内存中的位图并不需要占据连续的内存块。
图像dwWidth vs lpitch
lpitch的单位是字节,dwWidth的单位是像素。
lpitch中的字节数有时还包含了高速缓冲区的内存字节数。
dwWidth:内存中位图的一条线的开始和结束位置的内存地址之差(位图的宽度)。
pitch:内存中位图的一条线到下一条线开始位置的内存地址之差(宽度 + 缓存)。
使用教程
下载DirectX SDK库
头文件包含
#include <ddraw.h>
创建DirectDraw的对象实体
DirectDraw的对象实体代表了微机显示适配器,表示显示硬件,它包括了显示器和显卡还有显存,用它来代表整个显示系统。
LPDIRECTDRAW lpDD;
初始化DirectDrawCreate
HRESULT ddrval = DirectDrawCreate (NULL, &lpDD, NULL);
lpDD接受初始化成功的DirectDraw对象的地址,是整个DirectDraw接口的最高层领导。
显示设置SetCooperativeLevel()
lpDD->SetCooperativeLevel (GetActiveWindow(), DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
使DirectDraw对象与主窗口的消息挂上勾,期望DirectDraw以独占和全屏方式工作。
必须在创建DirectDraw对象之后,立即调用。
设置显示器的显示模式SetDispalyMode()
显示模式指的是显示器的当前设置,描述了显示器的分辨率和位深度。随着显示模式的尺寸和位深度的增加,它所需要的视频RAM也随之增加。
lpDD->SetDisplayMode( 640, 480, 8 );
把显示模式设为640*480,8位色彩模式(即256色)。可以调用EnumDisplayModes()来列举出显示器所支持的所有显示模式。
只有当DirectDraw对象为独占访问的控制程度时才能改变显示器的显示模式,如果DirectDraw对象运行为窗口模式,调用该函数会返回一个错误。
创建页面
翻页(Page flipping)
每一个页面都可以被轮流翻页至显示屏幕,静止的图象便开始运动起来。
主页面(primary surface):当前正好位于显示屏幕的页面。
后台缓存(Back buffers):其后等待翻页至屏幕的页面。
设置好一个翻页链结构。
一般至少建立前后两页(两块画板)。一边给别人看已经画好的另一块,等这块画好了,两块板就对调一下,让别人看新画好的这块。
页面DirectDrawSurface对象
DirectDrawSurface对象表示页面,用于绘制图像。代表了内存里的一个连续的线性的数据区。
页面可以有很多种表现形式,它既可以是可见的(屏幕的一部分或全部),称之为主页面(Primary Surface);也可以是作换页用的不可见页面,称之后台缓存(Back Buffer),在换页后,它成为可见;还有一种始终不可见的,称之为离屏页面(Off-screen Surface),用它来存储图象。其中,最重要的页面是主页面,每个DirectDraw应用程序都必须创建至少一个主页面,用它来代表屏幕上可见的区域(显示屏幕)。
LPDIRECTDRAWSURFACE lpDDSPrimary;
DDSURFACEDESC页面描述
DDSURFACEDESC surfaceDesc;
memset (&surfaceDesc, 0, sizeof(surfaceDesc));
surfaceDesc.dwSize = sizeof(surfaceDesc); //结构的大小
surfaceDesc.dwFlags = DDSD_CAPS; //指定DDSURFACEDESC结构的ddsCaps成员为可用
surfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; //指定要创建的是主页面
CreateSurface()
创建我们所请求的页面或换页链,并且返回指向主页面的IDirectDrawSurface接口的指针。
lpDD->CreateSurface (&surfaceDesc, &lpDDSPrimary, NULL);
如果函数调用成功,lpDDSPrimary将代表一个合法的主页面对象。在主页面上所绘制的图形将立即反映到你的显示屏幕上。
裁剪版Clipper
在窗口下,为了防止 DirectDraw 画到窗口外面去,需要加一个画框(裁剪板)。
LPDIRECTDRAWCLIPPER lpClipper;
//Create a clipper to ensure that our drawing stays inside our window.
lpDD->CreateClipper (0, &lpClipper, NULL);
//Setting it to our hWnd gives the clipper the coordinates from our window.
lpClipper->SetHWnd (0, hwnd);
//Attach the clipper to the primary surface.
lpDDSPrimary->SetClipper (lpClipper);
绘制
输出文字
if ( lpDDSPrimary->GetDC(&hdc) != DD_OK) return FALSE; //获得设备环境句柄
SetBkColor( hdc, RGB( 0, 0, 255 ) ); //设置背景颜色
SetTextColor( hdc, RGB( 255, 255, 0 ) ); //设置文字颜色
TextOut( hdc, 220, 200, szMsg1, lstrlen(szMsg1)); //输出文字
TextOut( hdc, 280, 240, szMsg2, lstrlen(szMsg2));
lpDDSPrimary->ReleaseDC(hdc); //释放资源
与Windows的GDI(图形设备接口)一致。
调用IDirectDrawSurface::Lock()方法和IDirectDrawSurface::UnLock()方法来给后台缓冲区加锁和解锁。
只对主表面(Surface)进行写操作。完成第一次弹出表面(Surface)操作时,会有一个明显的延时,所以只对主表面(Surface)缓冲区进行写操作是为了防止程序刚开始时显示不连贯。初始化函数和标题页只能放在主表面(Surface)缓冲区中。
只有表面(Surface)处于开锁状态,应用程序才能把它们由后台弹至前台。
调用IDirectDrawSurface::Unlock对表面(Surface)解锁后,指向表面(Surface)存储单元的指针就失效。
当把文本写到缓冲区后,调用IDirectDrawSurface::ReleaseDC()方法或者IDirectDrawSurface::Unlock()来解锁Surface,并释放句柄。
释放对象
f( lpDD != NULL ) //判断DirectDraw对象是否为空
{
if( lpDDSPrimary != NULL ) //判断主页面对象是否为空
{
lpDDSPrimary->Release(); //释放
lpDDSPrimary = NULL;
}
lpDD->Release(); //释放
lpDD = NULL;
}
抖动处理(Dithering)
在低位深度的图象中,由于颜色总数的限制,有些颜色无法显示出来。抖动处理(dithering)的方法指用交替的点图案去模拟在图象中不能使用的颜色,以提高显示效果。
在原始照片上,叠加一层白色噪声,让每个像素点的值都有所起伏。并且每个像素点起伏的概率为一个确定的值。(适度地)叠加了一层噪声之后,非但没有降低信号的质量,反而会带来提升。(想不通!!!)
信号的抖动处理
Direct3D
从DirectX 8.0开始,微软开始推荐开发人员使用Direct3D来处理2D图形,因为Direct3D提供了更加强大和灵活的图形处理能力。
DirectX Graphics
跨平台的图形API
如OpenGL和Vulkan
资料
DirectX中文手册
DirectDraw 参考
两个小时学会DirectDraw编程
游戏编程之十五 DirectDraw 的基本知识
游戏开发新手入门之DirectX入门