游戏开发论坛

 找回密码
 立即注册
搜索
查看: 4534|回复: 8

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

[复制链接]

41

主题

148

帖子

184

积分

注册会员

Rank: 2

积分
184
QQ
发表于 2003-11-26 20:09:00 | 显示全部楼层 |阅读模式
    显然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:rawAlpha( 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

        }

}

1万

主题

1万

帖子

2万

积分

管理员

中级会员

Rank: 9Rank: 9Rank: 9

积分
20484
发表于 2003-11-26 20:30:00 | 显示全部楼层

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

原创? 能转载吗?

8

主题

553

帖子

560

积分

高级会员

Rank: 4

积分
560
发表于 2003-11-26 20:39:00 | 显示全部楼层

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

GDI+完全可以取代DD。
至于用MMX实现alpha blend这个嘛,根据我的测试,使用硬件加速至少要快一个数量级!而且GDI+是建立在HAL层上的,也就是说,当你实现旋转,alpha blending是是硬件加速的。
如果说用MMX实现的alpha blending速度还可以接受的化,你可以试试实现旋转,你就会知道用高级指令集使用这些功能的时代已经过去了。

8

主题

553

帖子

560

积分

高级会员

Rank: 4

积分
560
发表于 2003-11-26 20:41:00 | 显示全部楼层

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

补充一点,GDI+比GDI更加容易掌握,我想就掌握的难易程度来说是:
GDI+ < GDI < DDraw

41

主题

148

帖子

184

积分

注册会员

Rank: 2

积分
184
QQ
 楼主| 发表于 2003-11-26 20:44:00 | 显示全部楼层

说明

此文章以及以后的系列文章都是我本人原创,我发表文章的目的给处在困境中的朋友实实在在的帮助,也希望能认识正在进行游戏开发的朋友大家共同进步,要是有没说清的地方加我QQ35830152,或者发邮件给我都可以.以后我所有的文章都在这里(GameRes.com)发表,有兴趣的朋友可以转载.

41

主题

148

帖子

184

积分

注册会员

Rank: 2

积分
184
QQ
 楼主| 发表于 2003-11-26 20:48:00 | 显示全部楼层

欢迎大家告诉我更新的技术

如果有GDI+这样的比DirectX更好的技术,可以一起探讨一下,最好有演示程序或源代码提供一下

8

主题

553

帖子

560

积分

高级会员

Rank: 4

积分
560
发表于 2003-11-26 20:53:00 | 显示全部楼层

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

GDI+只是GDI的接替者,MSDN上有很好例子,你几乎不用看文档,一看代码就知道GDI+怎么用。
GDI+只是可以替代DDraw,唯一的限制是必须在安装了sp3的win2k或者winxp,或者把gdiplus.dll copy到system32目录下的win98/2k。

5

主题

25

帖子

25

积分

注册会员

Rank: 2

积分
25
发表于 2003-11-28 01:59:00 | 显示全部楼层

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

如果能用 GPU 来做类似于 Alpha 混合的这种图象操作为什么还要用 CPU 来做?
还是用 D3D 吧

11

主题

274

帖子

669

积分

高级会员

Rank: 4

积分
669
发表于 2003-11-28 09:00:00 | 显示全部楼层

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

C = (C2*Alpha + C1*(1-Alpha))>>5

公式中的 >> 是什么意思啊!!

有谁能告诉我!!谢谢!!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-4-21 15:45

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表