directdraw:DirectDraw打造极速图形引擎(一)



  显然DirectDraw是Windows下写2D图形最好选择虽然Direct3D也可以写但是没DirectDraw简单方便特别对于初学者来就接触那么多和参数总不是件愉快所以我文章主要结合我做工作谈谈DirectDraw编程中些比较关键技术大多是我自己想出来我想先声明文章可以任意转载源代码可以任意使用和修改

   由于我是业余时间写文章所以只能每次发表希望我工作可以为大家游戏增光添彩同时我文章主要面向有基本CDirectDraw汇编和MMX编程经验朋友如果你对这些了解不够请先学习下再阅读也欢迎大家和我交流QQ是35830152EMAIL:[email protected]

   作为第我想先谈谈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位颜色值为RRRRRGGGGGGBBBBB555格式原理是显然我们每次处理个点似乎只能按照“拆分-分别运算-拆分”来写代码但是这样是低效想想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处理,而且不用(这会大大降低流水线效率).以后还会介绍动态光源,灰度图,动画控制等高级主题,欢迎大家指导,由于水平和打字原因,可能文章中会有,请谅解.

下面是任意Alpha混合运算

BOOL
CAresMaterial::DrawAlpha( LONG X, LONG Y, LPRECT pRect, BYTE Alpha )
{
unsigned __16 *pSrc, *pDest;
unsigned __32 A, PA;
unsigned __16 Width, Height;
unsigned __32 D1, D2;
RECT Rect;

A = Alpha & 0x1F;
PA = 0x1F - A;
Width = (unsigned __16)(pRect->right - pRect->left + 1);
Height = (unsigned __16)(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 _disibledevent=>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 );

TRUE;
}


下面是半透明Alpha混合运算

void
CAresMaterial::DrawAlpha1( LONG X, LONG Y, LPRECT pRect )
{

unsigned __16 *pSrc, *pDest;
unsigned __16 Width, Height, DW, DLeft;
unsigned __32 D1, D2;
unsigned __64 MASKER = 0x7BEF7BEF7BEF7BEF;
RECT Rect;

Width = (unsigned __16)(pRect->right - pRect->left);
Height = (unsigned __16)(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 pos _disibledevent=>

Tags:  directdrawerror directdraw不可用 directdraw加速 directdraw

延伸阅读

最新评论

发表评论