JeffMolofee(NeHe)的OPENGL教程-第一课[5]
由于全屏模式可能失败,用户可能决定在窗口下运行,我们需要在设置屏幕/窗口之前,再次检查fullscreen的值是TRUE或FALSE。
if (fullscreen) // 仍处于全屏模式吗?
{
如果我们仍处于全屏模式,设置扩展窗体风格为WS_EX_APPWINDOW,这将强制我们的窗体可见时处于最前面。再将窗体的风格设为WS_POPUP。这个类型的窗体没有边框,使我们的全屏模式得以完美显示。
最后我们禁用鼠标指针。当您的程序不是交互式的时候,在全屏模式下禁用鼠标指针通常是个好主意。
dwExStyle=WS_EX_APPWINDOW; // 扩展窗体风格
dwStyle=WS_POPUP; // 窗体风格
ShowCursor(FALSE); // 隐藏鼠标指针
}
else
{
如果我们使用窗口而不是全屏模式,我们在扩展窗体风格中增加了 WS_EX_WINDOWEDGE,增强窗体的3D感观。窗体风格改用 WS_OVERLAPPEDWINDOW,创建一个带标题栏、可变大小的边框、菜单和最大化/最小化按钮的窗体。
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; http // 扩展窗体风格
dwStyle=WS_OVERLAPPEDWINDOW; // 窗体风格
}
下一行代码根据创建的窗体类型调整窗口。调整的目的是使得窗口大小正好等于我们要求的分辨率。通常边框会占用窗口的一部分。使用AdjustWindowRectEx 后,我们的OpenGL场景就不会被边框盖住。实际上窗口变得更大以便绘制边框。全屏模式下,此命令无效。
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // 调整窗口达到真正要求的大小
下一段代码开始创建窗口并检查窗口是否成功创建。我们将传递CreateWindowEx()所需的所有参数。如扩展风格、类名字(与您在注册窗口类时所用的名字相同)、窗口标题、窗体风格、窗体的左上角坐标(0,0 是个安全的选择)、窗体的宽和高。我们没有父窗口,也不想要菜单,这些参数被设为NULL。还传递了窗口的实例,最后一个参数被设为NULL。
注意我们在窗体风格中包括了 WS_CLIPSIBLINGS 和 WS_CLIPCHILDREN。要让OpenGL正常运行,这两个属性是必须的。他们阻止别的窗体在我们的窗体内/上绘图。
if (!(hWnd=CreateWindowEx( dwExStyle, // 扩展窗体风格
"OpenGL", // 类名字
title, // 窗口标题
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle, // 必须的窗体风格属性
0, 0, // 窗口位置
WindowRect.right-WindowRect.left, // 计算调整好的窗口宽度
WindowRect.bottom-WindowRect.top, // 计算调整好的窗口高度
NULL, // 无父窗口
NULL, // 无菜单
hInstance, // 实例
NULL))) // 不向WM_CREATE传递任何东东
下来我们检查看窗口是否正常创建。如果成功, hWnd保存窗口的句柄。如果失败,弹出消息窗口,并退出程序。
{
KillGLWindow(); // 重置显示区
MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
下面的代码描述象素格式。我们选择了通过RGBA(红、绿、蓝、alpha通道)支持OpenGL和双缓存的格式。我们试图找到匹配我们选定的色彩深度(16位、24位、32位)的象素格式。最后设置16位Z-缓存。其余的参数要么未使用要么不重要(stencil buffer模板缓存和accumulation buffer聚集缓存除外)。
static PIXELFORMATDESCRIPTOR pfd=
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
bits,
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
16,
0,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0
};
//pfd 告诉窗口我们所希望的东东
file://上诉格式描述符的大小
// 版本号
// 格式必须支持窗口
// 格式必须支持OpenGL
// 必须支持双缓冲
// 申请 RGBA 格式
// 选定色彩深度
// 忽略的色彩位
// 无Alpha缓存
// 忽略Shift Bit
// 无聚集缓存
// 忽略聚集位
// 16位 Z-缓存 (深度缓存)
// 无模板缓存
// 无辅助缓存
// 主绘图层
// 保留
// 忽略层遮罩
如果前面创建窗口时没有错误发生,我们接着尝试取得OpenGL设备描述表。若无法取得DC,弹出错误消息程序退出(返回FALSE)。
if (!(hDC=GetDC(hWnd))) //取得设备描述表了么?
{
KillGLWindow(); // 重置显示区
MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
设法为OpenGL窗口取得设备描述表后,我们尝试找到对应与此前我们选定的象素格式的象素格式。如果Windows不能找到的话,弹出错误消息,并退出程序(返回FALSE)。
if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) // Windows 找到相应的象素格式了吗?
{
KillGLWindow(); // 重置显示区
MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
Windows 找到相应的象素格式后,尝试设置象素格式。如果无法设置,弹出错误消息,并退出程序(返回FALSE)。
if(!SetPixelFormat(hDC,PixelFormat,&pfd)) // 能够设置象素格式么?
{
KillGLWindow(); // 重置显示区
MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
正常设置象素格式后,尝试取得着色描述表。如果不能取得着色描述表的话,弹出错误消息,并退出程序(返回FALSE)。
if (!(hRC=wglCreateContext(hDC))) // 能否取得着色描述表?
{
KillGLWindow(); // 重置显示区
MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
如果到现在仍未出现错误的话,我们已经设法取得了设备描述表和着色描述表。接着要做的是激活着色描述表。如果无法激活,弹出错误消息,并退出程序(返回FALSE)。
if(!wglMakeCurrent(hDC,hRC)) // 尝试激活着色描述表
{
KillGLWindow(); // 重置显示区
MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
// Windows 找到相应的象素格式了吗?
{
KillGLWindow(); // 重置显示区
MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // 返回 FALSE
} Windows 找到相应的象素格式后,尝试设置象素格式。如果无法设置,弹出错误消息,并退出程序(返回FALSE)。 if(!SetPixelFormat(hDC,PixelFormat,&pfd)) // 能够设置象素格式么?
{
KillGLWindow(); // 重置显示区
MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // 返回 FALSE
} 正常设置象素格式后,尝试取得着色描述表。如果不能取得着色描述表的话,弹出错误消息,并退出程序(返回FALSE)。 if (!(hRC=wglCreateContext(hDC))) // 能否取得着色描述表?
{
KillGLWindow(); // 重置显示区
MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // 返回 FALSE
} 如果到现在仍未出现错误的话,我们已经设法取得了设备描述表和着色描述表。接着要做的是激活着色描述表。如果无法激活,弹出错误消息,并退出程序(返回FALSE)。 if(!wglMakeCurrent(hDC,hRC)) // 尝试激活着色描述表
{
KillGLWindow(); // 重置显示区
MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
一切顺利的话,OpenGL窗口已经创建完成,接着可以显示它啦。将它设为前端窗口(给它更高的优先级),并将焦点移至此窗口。然后调用ReSizeGLScene 将屏幕的宽度和高度设置给透视OpenGL屏幕。
ShowWindow(hWnd,SW_SHOW); // 显示窗口
SetForegroundWindow(hWnd); // 略略提高优先级
SetFocus(hWnd); // 设置键盘的焦点至此窗口
ReSizeGLScene(width, height); // 设置透视 GL 屏幕
跳转至 InitGL(),这里可以设置光照、纹理、等等任何需要设置的东东。您可以在 InitGL()内部自行定义错误检查,并返回 TRUE (一切正常)或FALSE (有什么不对)。例如,如果您在InitGL()内装载纹理并出现错误,您可能希望程序停止。如果您返回 FALSE的话,下面的代码会弹出错误消息,并退出程序。
if (!InitGL()) // 初始化新建的GL窗口
{
KillGLWindow(); // 重置显示区
MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
到这里可以安全的推定创建窗口已经成功了。我们向WinMain()返回TRUE,告知WinMain()没有错误,以防止程序退出。
return TRUE; // 成功
}