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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值