博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
DirectDraw打造极速图形引擎(Alpha混合)
阅读量:4988 次
发布时间:2019-06-12

本文共 4916 字,大约阅读时间需要 16 分钟。

显然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 + 1);    Height = (unsigned __int16)(pRect->bottom - pRect->top + 1);    D1 = (m_Desc.dwPitch - Width + 1)<<1 ;    D2 = (m_Desc.pAres->GetScreenPitch() - Width + 1)<<1 ;    SetRect( &Rect, X, Y, X+Width-1, Y+Height-1 );    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,16        mov cx,Width    LOOPA:        ror ecx,16        dec cx        jz DONE        ror ecx,16    LOOPB:        dec cx        jz NEXTLINE        //Process one point        mov ax,[esi]        mov dx,ax        shl eax,16        mov ax,dx        and eax,0x7E0F81F        movd edx,mm2        mul edx        movd mm0,eax        mov ax,[edi]        mov dx,ax        shl eax,16        mov ax,dx        and eax,0x7E0F81F        movd edx,mm3        mul edx        movd mm1,eax        paddd mm0,mm1        psrlq mm0,5        movd eax,mm0        and eax,0x7E0F81F        mov edx,eax        shr edx,16        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 + 1 );    pSrc = m_Desc.pData + pRect->top*m_Desc.dwPitch + pRect->left;    pDest = m_Desc.pAres->GetBackData() + Y*m_Desc.pAres->GetScreenPitch() + X;    DLeft = (Width % 4) + 1;    DW = (Width>>2) + 1;    D1 = (m_Desc.dwPitch - Width)<<1 ;    D2 = (m_Desc.pAres->GetScreenPitch() - Width)<<1 ;    SetRect( &Rect, X, Y, X+Width, Y+Height-1 );    __asm    {        mov esi,pSrc        mov edi,pDest        mov bx,DLeft        mov cx,Height        shl ecx,16        mov cx,DW    LOOPA:        ror ecx,16        dec cx        jz DONE        ror ecx,16    LOOPB:        dec cx        jz ENDLINE        //Process four points once        movq mm0,[esi]        movq mm1,[edi]        psrlq mm0,1        psrlq mm1,1        pand mm0,MASKER        pand mm1,MASKER        paddw mm0,mm1        movq [edi],mm0        add esi,8        add edi,8        jmp LOOPB    ENDLINE:        dec bx        jz NEXTLINE        mov ax,[esi]        mov dx,[edi]        shr ax,1        shr dx,1        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    }}

 

 

转载于:https://www.cnblogs.com/ziolo/p/4284874.html

你可能感兴趣的文章
安卓7.0手机拍照闪退问题解决
查看>>
ME525+ Defy+ 刷机指南[zz]
查看>>
支持触屏的jQuery轮播图插件
查看>>
差一点搞混了Transactional注解
查看>>
javascript基本函数
查看>>
前端公共库cdn服务推荐//提高加载速度/节省流量
查看>>
snprintf 返回值陷阱 重新封装
查看>>
asp.net GridView多行表头的实现,合并表头
查看>>
C#套打
查看>>
PolyCluster: Minimum Fragment Disagreement Clustering for Polyploid Phasing 多聚类:用于多倍体的最小碎片不一致聚类...
查看>>
【每日进步】July 2012
查看>>
327 作业
查看>>
sql 取汉字首字母
查看>>
bzoj4034: [HAOI2015]树上操作(树剖)
查看>>
${sessionScope.user}的使用方法
查看>>
WCF开发框架形成之旅---结合代码生成工具实现快速开发
查看>>
Spring事务管理
查看>>
linux下mysql配置文件my.cnf详解
查看>>
SublimeText快捷键操作
查看>>
Python开发 基礎知識 (未完代補)
查看>>