首页 | 互联网 | IT动态 | IT培训 | Cisco | Windows | Linux | Java | .Net | Oracle | 软件测试 | C/C++ | 嵌入式开发 | 存储世界 | 服务器
网络设备 | IDC | 安全 | 求职招聘 | 数字网校 | 网页设计 | 平面设计 | 技术专题 | 电子书下载 | 教学视频 | 源码下载 | 搜索 | 博客 | 论坛
 您现在的位置: 中国IT实验室 >> 游戏开发 >> 游戏开发文档 >> 正文
DirectDraw打造极速图形引擎(一)
来源:ChinaItLab 作者: 时间:2004-12-23


  显然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
  }
  }
【责编:admin】

中国IT教育热线咨询

相关文章
dx8中关于用索引缓冲渲染索引图元
作为一个状态机的OpenGL
OGRE中的四元数与旋转
[RGSS]Sprite类方法教学
[RGSS]去掉“战斗|逃跑”选项
推荐文章

 精彩友情推荐
·Asp源码 PHP源码
·CGI源码 JSP源码
·建站书籍教程
·服务器软件 .net源码
·建站工具软件
·IDC资讯大全
·机房品质万里行
·IDC托管必备知识
·全国IDC报价
·网站推广优化
 基础入门  开发文档
 最新推荐
  多数的Windows程序都需要Windows.h和Windowsx.h这两个头文件,要确保使用它们。当然,你还需要其它......
游戏引擎演化史
在Windows上安装OGRE的方法
关于滤镜遮罩概念,Sobel 遮罩
游戏开发新手入门之Windows编程
游戏开发新手入门之位图化图形
教你实现卡通渲染的另类勾边方法
游戏设计大师谈如何成为一名游戏设
Visual C#编写 3D游戏框架示例
真正的 Java 学习从入门到精通
游戏开发经验——游戏开发的基本常
  为什么要研究攻击行为在人类有记载的5600年的历史中,共计发生了14,400次战争;今天,平均一天要发生............
游戏开发中显示对话的特殊句法
游戏原型设计的介绍
网络游戏中的攻击行为
谈动作类游戏的必要条件
规则的多元分析模式
载入位图文件到DirectDraw
Archer Game Suite 是什么?
浅谈游戏企划-新手入门篇
暴雪称霸游戏业界的六大秘密绝招
骨骼动画及示例Skinned Mesh的解析
  培训中心