DirectDraw打造极速图形引擎(Alpha混合)
显然DirectDraw是Windows下写2D图形程序的最好选择,虽然Direct3D也可以写,但是没DirectDraw简单方便,特别对于初学者,一来就接触那么多函数和参数总不是件愉快的事,所以我的文章主要结合我做的工作,谈谈DirectDraw编程中一些比较关键的技术,大多是我自己想出来的。我想先声明,我的文章可以任意转载,源代码可以任意使用和修改。
由于我是业余时间写的文章,所以只能每次发表一篇,希望我的工作可以为大家的游戏增光添彩,同时我的文章主要面向有基本C++,DirectDraw,汇编和MMX编程经验的朋友,如果你对这些了解不够,请先学习一下再阅读。也欢迎大家和我交流,我的QQ是35830152,EMAIL:EUHO@SINA.COM。
作为第一篇,我想先谈谈Alpha混合的问题。这里32位色的图形模式我们不考虑,因为技巧并不多,占用显存和内存大,实际应用的也不多。我们把焦点放在16位色的模式上。我们把源点C2和Alpha通道点C1用Alpha混合,混合后得到点C,如果Alpha取0~1,公式如下:
C = C2*Alpha + C1*(1-Alpha)
如果Alpha取0~32,公式如下:
C = (C2*Alpha + C1*(1-Alpha))>>5
每个点由R,G,B 3个分量组成,所以上面的运算要分别对每个分量进行计算,如果整体计算,由于进位的关系我们会得到错误的结果。我们只考虑用得较多的565格式,即16位的颜色值为RRRRRGGGGGGBBBBB,555格式原理是一样的。显然我们每次处理一个点似乎只能按照“拆分-分别运算-拆分”来写代码,但是这样是低效的,想想1024*768模式下运算一帧要进行多少次运算,一定快不到哪里去。
Intel有段很长的代码,我没仔细看,也没试验,总觉得不太可靠(呵呵)。还看了GameRes上的一些相关文章,还是有值得参考的地方,就是觉得看了还是有些茫然。
下面说我的算法,首先说明这个快速算法是针对每个Alpha值建立一个函数进行运算,如果在一个函数里实现任意Alpha的运算,一次只能运算2个点,而且汇编代码是26行,而且有2次乘法,也用到了部分MMX加速。经过针对每一级Alpha的优化处理,每次处理4个点,代码只要8行左右,移位代替了乘法运算,完全发挥了MMX的威力。我只做了17级变换,0级和17级不用做,1到15原理一样,只有少少的不同,现在我举例半透明的算法,其他大家可以自己实现,有问题也可以和我交流。
Alpha运算中每个点3个色素,每个色素都要按上面那个公式运算,也就是每个色素要做2次乘法和一次加发,尽管可以变换一下不做浮点运算,但性能又能提高多少?我先讲一下我算法的一个基本原理,即“任意分组移位”,意思就是把一个数中分为N组,每组位数并不要求相同,我们用一次移位和一次与运算就能做到好像是每个分组移位而互不影响的效果。比半透明下Alpha=0.5,换成移位就是>>1,我们先把C右移一位,然后AND 一个2进制的数0111101111101111(0x7BEF),就完成了3个色素同时*0.5的运算,简单吧。
代码相信大家很容易就看懂了,大家把汇编部分和自己的程序结合就可以了,只要提供一些参数,比如页面数据指针和长度高度等资料.下次我会发布带Colorkey和Clip功能的代码,同样是MMX处理的,而且不用if(这会大大降低流水线的效率).以后还会介绍动态光源,灰度图,动画控制等高级主题,欢迎大家指导,由于水平和打字原因,可能文章中会有错误,请谅解.
下面是任意Alpha的混合运算
BOOL
CAresMaterial::DrawAlpha( LONG X, LONG Y, LPRECT pRect, BYTE Alpha )
{
unsigned __int16 *pSrc, *pDest;
unsigned __int32 A, PA;
unsigned __int16 Width, Height;
unsigned __int32 D1, D2;
RECT Rect; A = Alpha & 0x1F;
PA = 0x1F - A;
Width = (unsigned __int16)(pRect->right - pRect->left + );
Height = (unsigned __int16)(pRect->bottom - pRect->top + );
D1 = (m_Desc.dwPitch - Width + )<< ;
D2 = (m_Desc.pAres->GetScreenPitch() - Width + )<< ;
SetRect( &Rect, X, Y, X+Width-, Y+Height- );
m_Desc.pAres->BackToDILayer( &Rect );
pSrc = m_Desc.pData + pRect->top*m_Desc.dwPitch + pRect->left;
pDest = m_Desc.pAres->GetDILayerData() + Y*m_Desc.pAres->GetScreenPitch() + X; __asm
{
mov esi,pSrc
mov edi,pDest
movd mm2,A
movd mm3,PA mov cx,Height
shl ecx,
mov cx,Width LOOPA:
ror ecx,
dec cx
jz DONE
ror ecx, LOOPB:
dec cx
jz NEXTLINE
//Process one point
mov ax,[esi]
mov dx,ax
shl eax,
mov ax,dx
and eax,0x7E0F81F
movd edx,mm2
mul edx
movd mm0,eax mov ax,[edi]
mov dx,ax
shl eax,
mov ax,dx
and eax,0x7E0F81F
movd edx,mm3
mul edx
movd mm1,eax paddd mm0,mm1
psrlq mm0,
movd eax,mm0
and eax,0x7E0F81F
mov edx,eax
shr edx,
or eax,edx
mov [edi],ax inc esi
inc edi
inc esi
inc edi
jmp LOOPB NEXTLINE:
add esi,D1
add edi,D2
mov cx,Width
jmp LOOPA DONE:
emms
} m_Desc.pAres->DILayerToBack( &Rect ); return TRUE;
}
下面是半透明Alpha的混合运算
void
CAresMaterial::DrawAlpha1( LONG X, LONG Y, LPRECT pRect )
{ unsigned __int16 *pSrc, *pDest;
unsigned __int16 Width, Height, DW, DLeft;
unsigned __int32 D1, D2;
static unsigned __int64 MASKER = 0x7BEF7BEF7BEF7BEF;
RECT Rect; Width = (unsigned __int16)(pRect->right - pRect->left);
Height = (unsigned __int16)(pRect->bottom - pRect->top + );
pSrc = m_Desc.pData + pRect->top*m_Desc.dwPitch + pRect->left;
pDest = m_Desc.pAres->GetBackData() + Y*m_Desc.pAres->GetScreenPitch() + X; DLeft = (Width % ) + ;
DW = (Width>>) + ; D1 = (m_Desc.dwPitch - Width)<< ;
D2 = (m_Desc.pAres->GetScreenPitch() - Width)<< ;
SetRect( &Rect, X, Y, X+Width, Y+Height- ); __asm
{
mov esi,pSrc
mov edi,pDest
mov bx,DLeft mov cx,Height
shl ecx,
mov cx,DW LOOPA:
ror ecx,
dec cx
jz DONE
ror ecx, LOOPB:
dec cx
jz ENDLINE
//Process four points once
movq mm0,[esi]
movq mm1,[edi]
psrlq mm0,
psrlq mm1,
pand mm0,MASKER
pand mm1,MASKER
paddw mm0,mm1
movq [edi],mm0 add esi,
add edi,
jmp LOOPB ENDLINE:
dec bx
jz NEXTLINE
mov ax,[esi]
mov dx,[edi]
shr ax,
shr dx,
and ax,0x7BEF
and dx,0x7BEF
add ax,dx
mov [edi],ax
inc esi
inc esi
inc edi
inc edi
jmp ENDLINE NEXTLINE:
add esi,D1
add edi,D2
mov cx,DW
mov bx,DLeft
jmp LOOPA DONE:
emms
}
}
DirectDraw打造极速图形引擎(Alpha混合)的更多相关文章
- D3D中深度测试和Alpha混合的关系
我在学习D3D的深度测试和Alpha混合的时候,有一些遗憾.书上提供的例子里说一定要先渲染不透明物体,再渲染透明物体,对渲染状态的设置也有特殊要求.我看的很晕.自己查图形学的书,上网找资料,结果还是糊 ...
- 16位图像Alpha混合的实现(用汇编写的,比MMX还要快)
Alpha 混合的算法很简单,基于下面的公式就可以实现: D := A * (S - D) / 255 + D D 是目标图像的像素, S 是源图像的像素 A 是 Alpha 值, 0 为全透明, 2 ...
- 【转载】Alpha混合物体的深度排序
原文:Alpha混合物体的深度排序 先说个题外话, 本来我想解答一下最近Creators Club论坛上经常出现的一个问题, 意外的是在网上竟然找不到什么全面的答案.. 这是个有着复杂答案的简单问题: ...
- 【转载】D3D深度测试和Alpha混合
原文:D3D深度测试和Alpha混合 1. 深度测试 a) 深度缓冲区:屏幕上每个像素点的深度信息的一块内存缓冲区.D3D通过比较当前绘制的像素点的深度和对应深度缓冲区的点 ...
- Alpha混合
ShaderLab syntax: Blending 混合 Blending is used to make transparent objects. 混合是用来制作透明物体的. When graph ...
- 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记8——载入三维模型&Alpha混合技术&深度测试与Z缓存
第17章 三维游戏模型的载入 主要是如何从3ds max中导出.X文件,以及如何从X文件加载三维模型到DirextX游戏程序里.因为复杂的3D物体,要用代码去实现,那太反人类了,所以我们需要一些建模软 ...
- Shader第十三讲 Alpha混合
http://blog.sina.com.cn/s/blog_471132920101d8z5.html Alpha Blending,中文译作Alpha混合Blending就是控制透明的.处于光栅化 ...
- 【STM32H7教程】第56章 STM32H7的DMA2D应用之刷色块,位图和Alpha混合
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第56章 STM32H7的DMA2D应用之刷色块, ...
- 深度排序与alpha混合
原文: https://blogs.msdn.microsoft.com/shawnhar/2009/02/18/depth-sorting-alpha-blended-objects/ 翻译:李现民 ...
随机推荐
- Error: L6218E: Undefined symbol TIM_ARRPreloadConfig (referred from pwm_output.o).
出错原因:模板FWLIB中没有添加stm32f10x_tim.c文件.添加即可 一般利用库开发,将ppp.c(ppp.c又调用了库stm32f10x_xx.h)写好之后的调用步骤: 1 将ppp.c和 ...
- webuploader在同一个页面支持多个按钮实例
之前在时候用到webuploader ,起初是支持单实例,后来要求支持多实例. webuploder API网址,如果不懂我说的可以去查看http://fex.baidu.com/webuploade ...
- Web Uploader文件上传&&使用webupload有感(黄色部分)
引入资源 使用Web Uploader文件上传需要引入三种资源:JS, CSS, SWF. <!--引入CSS--> <link rel="stylesheet" ...
- Python进阶03 模块
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们之前看到了函数和对象.从本质上来说,它们都是为了更好的组织已经有的程序,以方便 ...
- 15个IT技术人员必须思考的问题
行内的人自嘲是程序猿.屌丝和码农,行外的人也经常拿IT人调侃,那么究竟是IT人没有价值,还是没有仔细思考过自身的价值? 1.搞IT的是屌丝.码农.程序猿? 人们提到IT人的时候,总会想到他们呆板.不解 ...
- C++学习42 输入和输出的概念
我们经常用到的输入和输出,都是以终端为对象的,即从键盘输入数据,运行结果输出到显示器屏幕上.从操作系统的角度看,每一个与主机相连的输入输出设备都被看作一个文件.除了以终端为对象进行输入和输出外,还经常 ...
- EXT dateRange
VTYPES: Ext.apply(Ext.form.VTypes, { daterange: function (val, field) { var date = field.parseDate(v ...
- 列出当前ARM开发板系统加载的模块
lsmod 列出当前系统中加载的模块,其中左边第一列是模块名,第二列是该模块大小,第三列则是使用该模块的对象数目
- vs2013 ie10
http://blog.163.com/qimo601@126/blog/static/1582209320143354446462/ @ECHO OFF :IE10HACK REG A ...
- html5—— 应用程序缓存
使用 HTML5,通过创建 cache manifest 文件,可以轻松地创建 web 应用的离线版本. 什么是应用程序缓存(Application Cache)? HTML5 引入了应用程序缓存,这 ...