DirectX 之 DirectDraw 窗口模式(转载)

在窗口模式下使用 DirectDraw , 最大的痛苦是不能使用换页操作(Flip). 但是有许多人还是喜欢在窗口模式下进行游戏.

    首先, 窗口模式下创建一个 IDirectDraw 接口对象和全屏模式下是一样的, 不同的是, 在选择协作模式和不能改变屏幕分辨率. (当然你坚决要改变, 一定要有礼貌的改变.)

 // 设置协作级别,窗口化下使用 DDSCL_NORMAL 标志.
 if (FAILED(m_x2d_lpDDraw->SetCooperativeLevel(m_x2d_hWnd, DDSCL_NORMAL)))
  return (E_FAIL);

 // 使用 DirectDraw 接口对象创建 DirectDrawSurface 主页面对象.
 DDSURFACEDESC2 ddsd;
 INIT_DXSTRUCT(ddsd);
 ddsd.dwFlags = DDSD_CAPS;
 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
 if (FAILED(m_x2d_lpDDraw->CreateSurface(&ddsd, &m_x2d_lpDDrawPrimarySurface, NULL)))
  return (E_FAIL);

 // 创建一个离屏页面
 INIT_DXSTRUCT(ddsd);
 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
 ddsd.dwWidth = width;
 ddsd.dwHeight = height;
 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;

 if (FAILED(m_x2d_lpDDraw->CreateSurface(&ddsd, &m_x2d_lpDDrawBackSurface, NULL)))
 return (E_FAIL);

 /*    在这里省略掉给这个离屏页面附属上裁剪器,
 下面使用到这个离屏页面的是已经附属上裁减器的.    */


 LPDIRECTDRAWCLIPPER lpDDClipper = NULL;
 // 创建裁剪器.
 if (FAILED(m_x2d_lpDDraw->CreateClipper(0, &lpDDClipper, NULL)))
  return (E_FAIL);

 // 与窗口工作区关联.
 if (FAILED(lpDDClipper->SetHWnd(0, m_x2d_hWnd)))
 {
  SAFE_RELEASE(lpDDClipper);
  return (E_FAIL);
 }

 if (FAILED(m_x2d_lpDDrawPrimarySurface->SetClipper(lpDDClipper)))
 {
  SAFE_RELEASE(lpDDClipper);
  return (E_FAIL);
 }
 SAFE_RELEASE(lpDDClipper);

    给主页面设置裁剪器, 是为了窗口在超出(超出屏幕的显示部分)桌面时能正常工作.实际上主页面就是你的桌面.

现在桌面上有许多窗口在运行, 我们不能胡乱的在桌面上乱画, 否则其他的窗口可能抱怨. 我们要知道我们的窗口工作区位置, 然后我们在这个工作区内工作.

GetClientRect(m_x2d_hWnd, &m_x2d_ClientRect);
ClientToScreen(m_x2d_hWnd, (LPPOINT)&m_x2d_ClientRect);
ClientToScreen(m_x2d_hWnd, (LPPOINT)&m_x2d_ClientRect+1);

m_x2d_ClientRect 保存的是我们的窗口工作区(客户区)位置.

然后我们可能这样用:
m_x2d_lpDDrawPrimarySurface->Blt(&m_x2d_ClientRect, m_x2d_lpDDrawBackSurface, NULL, DDBLT_WAIT, NULL));

这个位转换目标位置就是我们的工作区. 因为我们给主页面附属了裁剪器, 所以不能再用BltFast来位转换了.

如果我们像这样用, 可能看到一个杂乱的桌面.
RECT rct = { 0, 0, 300, 123};
m_x2d_lpDDrawPrimarySurface->Blt(&rct, surface, NULL, DDBLT_WAIT, NULL));
这样的后果是:
在桌面的 X = 0, Y = 0 位置, 画上 宽 = 300, 高 = 123 的 surface 图形.

在窗口模式下, 一定要正确获得自己的工作区, 当窗口移动或者改变大小, 我们因该有所行动.

case WM_MOVE:
case WM_SIZE:
 GetClientRect(m_x2d_hWnd, &m_x2d_ClientRect);
 ClientToScreen(m_x2d_hWnd, (LPPOINT)&m_x2d_ClientRect);
 ClientToScreen(m_x2d_hWnd, (LPPOINT)&m_x2d_ClientRect+1);
 break;

还有, 当窗口失去焦点(活动), 应该停止在继续向主页面绘画. 否则, 你画的将覆盖掉在窗口上的其他窗口的内容.

case WM_ACTIVATE:
 {
  switch((LOWORD(wParam)))
  {
  case WA_ACTIVE:
  case WA_CLICKACTIVE:
   // 活动, 可以继续向主页面绘画了.
   Active(true);
   break;
  case WA_INACTIVE:
   // 不活动, 停止向主页面绘画.
   Active(false);
   break;
  default:
   break;
  }
 }

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值