使用高彩模式
上一章中说了可以用16位的色彩深度,但是16位的色彩深度的数据表示模式可以有两种:Alpha.5.5.5(or X.5.5.5) 和 5.6.5(这是16位色彩最常用的)。对于使用哪种16位的色彩模式这个是由硬件决定的,我们不能决定。但是我们可以查询,然后按照硬件支持的模式来填写。
我们可以调用方法IDIRECTDRAWSURFACE7::GetPixelFormat(),同时这个函数需要一个LPDDPIXELFORMAT的结构,其中的dwFlags 和 dwRGBBitCount成员记录着像素格式(8位索引或者RGB模式)
示例代码如下:
DDPIXELFORMAT ddpixel;  
memset(&ddpixel, 0, sizeof(ddpixel) ); 
ddpixel.dwSize = sizeof(ddpixel);  
lpddsprimary->GetPixelFormat(&ddpixel);
                                   
if (ddpixel.dwFlags & DDPF_RGB)  // RGB Mode 
{   
        switch(ddpixel.dwRGBBitCount)   


        {   


                case 15:  // 5.5.5


                break;  


                case 16:  // 5.6.5    


                break;                                  


                case 24:                                         


                break;                    


                case 32:           


                break;           


                default:     


                break;        


        }       
}         
else  // ddpixel.dwFlags & DDPF_PALETTEINDEXED8 == TRUE
{           


             

}      
对于32位的模式也可以用以上判断代码,并且将填写颜色的代码写在case 32:里面。
32位色彩的两种模式为:Alpha.8.8.8 和 X.8.8.8。对于后面的一种,建议将X的8位置为0。
双缓冲
现在我们已经可以对表面进行修改了。这样也就是通过视频控制器直接将每一帧都光栅化。这对于静态图像来说已经很好了。但是如果是动画呢?可能就不是非常平滑。我们就需要使用双缓冲技术。即先申请一个和主表面同样大小的数组(或者数据块),将色彩数据填写进这个数组中,最后再复制进加锁的表面中。在复制的时候我们需要注意表面是否线形的问题。如果是线性的,那么我们可以把整个数据块一并复制;如果不是,那么我们只能一行行来复制。(其中这种技术我们并不会真正的用到,除非数据块很小。因为DirectDraw提供给我们更好的动态表面)
表面动态
离屏表面一——后备缓冲。创建后备缓冲的目的是用DirectDraw的方式来实现对双缓冲功能的仿真。如果创建了DirectDraw后备缓冲(通常在VRAM中),读写会非常快。你可以将它和主表面进行页面切换,这比双缓冲方案下所需做的内存复制要快得多。
创建一个关联有后备缓冲的主表面步骤:
  1. 首先,你要将DDSD_BACKBUFFERCOUNT加到dwFlags标志字段,向DirectDraw表明DDSURFACEDESC2结构的dwBackBufferCount字段有效,其中含有后备缓冲的数目。
  2. 其次,将控制标志DDSCAPS_COMPLEX 和 DDSCAPS_FLIP加到DDSURFACEDESC2结构的特性描述字段ddsCaps.dwCaps上。
  3. 最后,像通常一样创建主表面。从它调用IDIRECTDRAWSURFACE7::GetAttachedSurface() 以得到后备缓冲。

示例代码:

LPDIRECTDRAWSURFACE7 lpddsback;



ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;                                      


ddsd.dwBackBufferCount = 1;                                                                                         


ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;                                                                                                                    


lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL);                                                


ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;                                                       


lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback);                    

注意其中红色属性。

这样一来,以后只要每次都在后备缓冲绘图,然后调用Flip方法进行表面切换,就可以实现快速的翻页。

示例代码:

lpddsprimary->Flip(NULL, DDFLIP_WAIT);

需要注意两点,1.翻页总是由主表面执行的。2.翻页前主表面或者后备缓冲表面都必须解锁。

使用Blitter

DirectDraw中在各个表面之间进行Blitter和Windows编程中的各个DC之间Blt有点类似,不过DirectDraw中可以做的更加好,更加快。有两个达到这个功能的函数:Blt() 和 BltFast()。他们的不同是前者会调用裁减器而后者不用但是速度更快。

示例代码:

DDBLTFX ddbltfx;                                                           


RECT dest_rect;  

memset(&ddbltfx, 0, sizeof(ddbltfx));  

ddbltfx.dwSize = sizeof(ddbltfx);  

ddbltfx.dwFillColor = RGB(0, 0, 0);  // or color index in 8 bit mode 

dest_rect.left = x1; 

dest_rect.top = y1;  

dest_rect.right = x2;

dest_rect.bottom = y2; 

lpddsprimary->Blt(&dest_rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT,  &ddbltfx);  

在上面的例子中,调用Blt函数有两个参数是NULL,因为这个例子比较特殊,他并没有从另外一个已有表面复制,而是用一种颜色对自己进行填充。这是Blt的一个特殊用法。一般情况下,我们总是从另外一个表面(可能是离屏表面)向目标表面(可能是后备缓冲)进行填充。注意,函数调用的参数中的那个表面是源表面。

上面Blt函数中的第一个NULL参数表示源表面要复制过来的区域,那么要是这块区域对应到目标表面的区域出现了问题怎么办?也就是说,他超出了整个目标表面。如要从源(0,0, 100, 100)复制到目标的(600, 400, 700, 600)(这里保持两个RECT大小一样,不一样的情况以后会说),但是目标表面只有640*480的大小,也就是说没有(700,600)这点,有一部分会超出表面。所以这个时候我们只要复制(600, 400, 640, 480)这样一块就可以了。其余部分需要裁减掉。

裁减器

你需要做的就是创建一个IDirectDrawClipper,传给它有效的裁减区域,然后将它同表明连接。具体步骤如下:

  1. 创建DirectDraw裁减器对象。
  2. 创建裁减序列。
  3. 用IDIRECTDRAWCLIPPER::SetClipList() 将裁减序列发送给裁减器。
  4. 用IDIRECTDRAWSURFACE7::SetClipper()将裁减器同窗口和/或表面相关联。

示例代码:

LPDIRECTDRAWCLIPPER lpddclipper = NULL;

lpdd->CreateClipper(0, &lpddclipper, NULL);

lpddclipper->SetClipList(&rgndata, 0);

lpddsurface->SetClipper(&lpddclipper);

其中的rgndata变量是一个RGNDATA结构,这是一个动态的结构。由两个成员(一个结构,一个指针)组成。用这个结构来创建裁减序列。

离屏表面

接下来我们说一下离屏表面(通用的非主表面也非后备表面)的创建。

基本同创建主表面一样,只是对于ddsd结构的设置稍有以下不同。

  1. 你必须将ddsd.dwFlags设置为 DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT
  2. 你必须在ddsd.dwWidth, ddsd.dwHeight中设置所请求的表面的尺寸。
  3. 必须将ddsd.dwCaps设置为DDSCAPS_OFFSCREENPLAIN | memory_flags,其中memory_flags决定在那里创建表面。

示例代码:

LPDIRECTDRAWSURFACE lpdds;

DDRAW_INIT_STRUCT(ddsd);

ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;

ddsd.dwWidth = 1024;

ddsd.dwHeight = 768;

ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;

lpdd->CreateSurface(&ddsd, &lpdds, NULL);

这样就创建了一个和主表面兼容的离屏表面。另外建议在创建离屏表面的时候总是从大到小的创建。

现在你就可以像使用一般的表面一样来进行锁定,位图复制和Blitter操作了。

色彩键

当我们在复制位图的时候可能其中的某些颜色(透明色)我们并不想复制。那么我们就可以通过将他们设置成源色彩键。例如我们要把色彩0作为色彩键,可以这么做:

示例代码:

DDCOLORKEY color_key;

color_key.dwColorSpaceLowValue = 0;

color_key.dwColorSpaceHighValue = 0;

lpdds->SetColorKey(DDCKEY_SRCBLT, &color_key);

高级DirectDraw的更多相关文章

  1. DirectDraw用到的DDSURFACEDESC2

    DDSURFACEDESC2 结构定义一个需求的平面.下面的例子演示了结构的定义和标志位的设定: // Create the primary surface with one back buffer. ...

  2. 初次接触:DirectDraw

    第六章 初次接触:DirectDraw 本章,你将初次接触DirectX中最重要的组件:DirectDraw.DirectDraw可能是DirectX中最强大的技术,因为其贯穿着2D图形绘制同时其帧缓 ...

  3. DirectX中文手册

    目  录 第一章 DirectX基础(初级篇) 第一节  什么是DirectX 一.什么是DirectX ? 二.DirectX的组成部分 三.关于DirectDraw 四.为什么要使用DirectD ...

  4. DirectDraw打造极速图形引擎(Alpha混合)

    显然DirectDraw是Windows下写2D图形程序的最好选择,虽然Direct3D也可以写,但是没DirectDraw简单方便,特别对于初学者,一来就接触那么多函数和参数总不是件愉快的事,所以我 ...

  5. DirectDraw

    一.DirectDraw接口 DirectDraw接口图如下: 1.IUnknown:所有COM对象都必须从这个基本接口派生 2.IDirectDraw:这是开始使用DirectDraw时必须创建的主 ...

  6. MySQL高级知识- MySQL的架构介绍

    [TOC] 1.MySQL 简介 概述 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司. MySQL是一种关联数据库管理系统,将数据保存在不同的表中,而 ...

  7. PayPal高级工程总监:读完这100篇论文 就能成大数据高手(附论文下载)

    100 open source Big Data architecture papers for data professionals. 读完这100篇论文 就能成大数据高手 作者 白宁超 2016年 ...

  8. 马哥linux运维初级+中级+高级 视频教程 教学视频 全套下载(近50G)

    马哥linux运维初级+中级+高级 视频教程 教学视频 全套下载(近50G)目录详情:18_02_ssl协议.openssl及创建私有CA18_03_OpenSSH服务及其相关应用09_01_磁盘及文 ...

  9. JS高级前端开发群加群说明及如何晋级

    JS高级前端开发群加群说明 一.文章背景: 二. 高级群: 三. 加入方式: 四. 说明:   一.文章背景: 去年年初建了几个群,在不经意间火了,一直排在“前端开发”关键字搜索结果第一名.当然取得这 ...

随机推荐

  1. Jmeter Smock Test规范设计

    Jmeter Smock Test规范设计 一.Smock Test物料 1.开发运行工具Jmeter,(下载地址: http://jmeter.apache.org/download_jmeter. ...

  2. 用icas下载文件报错

    前段时间服务器升级,过程中测试到报表下载,报表下载要用到icas,用的是sdts-client.jar,但是此jar包有两种连接模式,分别为: public static final SdtsConn ...

  3. getopt for windows

    Glibc库里有个getopt用于解析命令行参数,挺方便的,下面的是别人从Glibc源码的获取的几个getopt相关的文件,已经将平台相关的修改掉,windows下可以调用,本来是要用没用到就没去看正 ...

  4. BZOJ 2141: 排队 [CDQ分治]

    题意: 交换序列中两个元素,求逆序对 做分块做到这道题...一看不是三维偏序嘛.... 作为不会树套树的蒟蒻就写CDQ分治吧.... 对时间分治...x排序...y树状数组... 交换拆成两个插入两个 ...

  5. BZOJ 3550: [ONTAK2010]Vacation [单纯形法]

    有3N个数,你需要选出一些数,首先保证任意长度为N的区间中选出的数的个数<=K个,其次要保证选出的数的个数最大. 好像都是费用流... 单纯性裸题呀... 注意每个数最多选1次 #include ...

  6. BZOJ 2809: [Apio2012]dispatching [主席树 DFS序]

    传送门 题意:查询树上根节点值*子树中权值和$\le m$的最大数量 最大值是多少 求$DFS$序,然后变成区间中和$\le m$最多有几个元素,建主席树,然后权值线段树上二分就行了 $WA$:又把边 ...

  7. Centos-7 + Docker-1.12 中 devicemapper + direct_lvm 的 Docker 存储配置

    html,body { font-size: 12pt } body { font-family: Helvetica, "Hiragino Sans GB", "微软雅 ...

  8. 游戏服务器设计之NPC系统

    游戏服务器设计之NPC系统 简介 NPC系统是游戏中非常重要的系统,设计的好坏很大程度上影响游戏的体验.NPC在游戏中有如下作用: 引导玩家体验游戏内容,一般游戏内有很多主线.支线任务,而任务的介绍. ...

  9. ACE_TEST1.obj : error LNK2019: 无法解析的外部符号

    ACE_TEST1.obj : error LNK2019: 无法解析的外部符号 "int __cdecl ace_main_i(int,char * * const)" (?ac ...

  10. MySQL中四种常用存储引擎的介绍

    MySQL常用的四种引擎的介绍 (1):MyISAM存储引擎: 不支持事务.也不支持外键,优势是访问速度快,对事务完整性没有 要求或者以select,insert为主的应用基本上可以用这个引擎来创建表 ...