【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 2428|回复: 0

fswindows (在DirectX 全屏独占 方式下显示对话框和任意窗口)

[复制链接]
发表于 2006-2-14 10:26:23 | 显示全部楼层 |阅读模式
DirectX SDK
在全屏方式(full-screen mode)中显示一个窗口 [语言: C++ ]

用全屏方式,DirectDraw 拥有对显示的完全控制权。因此,通过GDI 建立的对话框和其他窗子是不能正常显示的。 不过,通过使用特别的技术你能合并一个 Windows 对话框,HTML 帮助,或者其它任何一种窗口 到你的应用程序当中。

FSWindow 例子描述了一个对话框如何在全屏模式的应用程序中显示并更新, 以及鼠标的点击和键盘的输入工作的如同这个对话框由 GDI 显示一样。

在 FSWindow 里,对话框被建立和"显示" 如同一个普通的对话框窗口:

hWndDlg = CreateDialog(g_hInstance,
MAKEINTRESOURCE(IDD_DIALOG_SAMPLE),
hWnd, (DLGPROC) SampleDlgProc);
ShowWindow(hWndDlg, SW_SHOWNORMAL);

当然,在这点对话框只在被隐藏的 GDI 表面上被显示。它不在由 DirectDraw 控制的主要表面(primary surface)上出现。

如果你的显卡硬件加速能力包括 DDCAPS2 _ CANRENDERWINDOWED ( 参考 DDCAPS 结构),显示和更新对话框是非常简单的事情。程序只需调用 IDirectDraw7:FlipToGDISurface 方法,使 GDI 表面为主要表面。今后,对对话框的全部更新将被自动显示,因为 GDI 现在将直接对前台缓冲区进行重画更新。应用程序还是继续对后备缓冲区进行重画更新,并且通过每次的更新 DirectDraw 都将后备缓冲区的被赋值到前台缓冲区。 对话框并没有被覆盖是因为对于应用程序的窗口来说前台缓冲区已经被裁剪(clipped )了一部分,对话框就正好裁剪了被省略的部分。

下列代码,在 FSWindow_Init 函数中,建立裁剪器,把它与应用程序窗口关联起来,并且把 GDI 表面(surface )带到前台:

if (ddObject->CreateClipper(0, &ddClipper, NULL) == DD_OK)
ddClipper->SetHWnd(0, hwndAppWindow);
ddObject->FlipToGDISurface();

然后,在 FSWindow_Update 函数中,下列代码 复制后备缓冲区重画的内容 到裁剪区域。

ddFrontBuffer->SetClipper(ddClipper);
ddFrontBuffer->Blt(NULL, ddBackBuffer, NULL, DDBLT_WAIT, NULL);

请注意,因为 GDI 表面就是主要表面,Windows 继续显示鼠标。 (如果应用程序使用独占级别的 DirectInput 来控制鼠标设备的话,这将不会发生。)

对于没有 DDCAPS2_CANRENDERWINDOWED 支持的硬件来说,在全屏方式下显示并且更新一个窗口就显得有些错综复杂了。这样的话,应用程序应该负责获得由 GDI 创建的窗口的全部图像并且在全屏重画更新完成后将它们复制到后备缓冲区。之后全部后备缓冲区会和平常一样被替换到前台。

FSWindow 范例提供两种不同的方法为操作窗口的显存,这取决于内容是静止还是动态的(小猫:这里是指对话框的内容)。 静止的内容的这种方法更迅速因为它从记忆设备上下文而不是屏幕设备上下文中进行相关复制。这种方法应该用于不改变的窗口,例如信息的对话框的窗子。 (不过记住那个,除非在需要回应事件的时候你手工不断更新位图,否则哪怕如同按按钮这样基础的动画效果用户也是不能看见的。)

如果内容是静止的,当窗子初始化时,FSWindow 调用 CreateBMPFromWindow 函数。 此函数创建一个位图并且将窗口的内容复制进去。位图的句柄被存储在全局变量 hwndFSWindowBMP 中。 每当主要表面正要被更新时,这个位图将被复制到后备缓冲区,如下:

if (FSWindow_IsStatic)
{
hdcMemory = CreateCompatibleDC(NULL);
SelectObject(hdcMemory, hwndFSWindowBMP);
BitBlt(hdcBackBuffer, x, y, cx, cy, hdcMemory, 0, 0, SRCCOPY);
DeleteDC(hdcMemory);
}

如果, 另一方面,窗口的内容是动态的,下列代码被执行。 直接从 GDI 表面(以hdcScreen 设备上下文描述)复制图像到后备缓冲区。

BitBlt(hdcBackBuffer,x,y,cx,cy,hdcScreen,x,y,SRCCOPY);
坐标系相对于 GDI 表面上窗体的位置和尺寸,经由对 GetWindowRect 函数的调用得到。

当FSWindow 应用正在没有 DDCAPS2_CANRENDERWINDOWED 支持的硬件上运转时,它不使用 GDI 表面,因此 Windows 不能显示鼠标。 应用程序接管这项任务,通过获得关于光标的信息并且在页面转换前在背面缓冲区上显示它。



----------------------------------------------------------------------------

用下面的代码就可以为主表面挂接上Clipper:

// 首先创建一个Clipper:
LPDIRECTDRAWCLIPPER clipper;
lpDD->CreateClipper(0, &clipper, 0);

// 将clipper与主窗口进行关联:
clipper->SetHWnd(0, hMainWnd);

// 将clipper挂入主表面:
lpDDSMain->SetClipper(clipper);

// 删除clipper
clipper->Release();
}

需要注意的是:表面挂接clipper后,就无法在这个表面上
使用Flip()和BltFast()函数了。所以,你必须要使用Blt()
函数来把BackBuffer上的内容拷贝到主表面上。而且在我实际运用中发现主画面联接裁剪器后,显示白屏。去掉lpDDSMain->SetClipper(clipper)这行代码,并且用Blt来更新画面后一切将显示正常。并且能显示GID窗口,不知是何原因?

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-2-6 01:48

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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