明白了显示模式的设置方法后,实现OpenGL的全屏模式就不难了。下面我们来看一个全屏的应用,由于全屏的程序框架有了较多的改变,我们将主要代码列出来加以说明。其中InitInstance是全屏实现的关键。
/* 创建OpenGL窗口
* width - 窗口宽度
* height - 窗口高度
* bits - 颜色位数(8/16/24/32)
*/
BOOL InitInstance(int width, int height, int bits)
{
GLuint PixelFormat; // 像素个数
DWORD dwExStyle; //扩展窗口风格
DWORD dwStyle; //窗口风格
RECT Rt;
Rt.left=(long)0;
Rt.right=(long)width;
Rt.top=(long)0;
Rt.bottom=(long)height;
hInst = GetModuleHandle(NULL); //取得当前应用程序实例句柄
MyRegisterClass(hInst); //注册窗口类
//新增加有关全屏模式
if (fullscreen) //如果是全屏模式
{
DEVMODE dmScreenSettings; // Device Mode
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
//确保在Win9x和WinNT下可以正确的修改显示模式
if(!EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&dmScreenSettings))
{
MessageBox(NULL, "无法列举显示设备!", "Error", MB_OK);
return FALSE;
}
dmScreenSettings.dmSize=sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = width;
dmScreenSettings.dmPelsHeight = height;
dmScreenSettings.dmBitsPerPel = bits;
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH
|DM_PELSHEIGHT;
//改变显示模式
int hr = ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN);
if(hr != DISP_CHANGE_SUCCESSFUL)
{
if (MessageBox(NULL,"你的设备不支持全屏模式!","Error",MB_OK)==IDYES)
{
//如果选择了YES,则仍然使用窗口模式
fullscreen=FALSE;
}
else
{
MessageBox(NULL,"程序即将关闭!","Error",MB_OK);
return FALSE;
}
}
}
//在全屏模式下还要设置窗口风格,隐藏光标(不是必须)
if (fullscreen)
{
dwExStyle=WS_EX_APPWINDOW;
dwStyle=WS_POPUP;
ShowCursor(FALSE);
}
else //窗口模式下
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle=WS_OVERLAPPEDWINDOW;
}
//对窗口进行微调
AdjustWindowRectEx(&Rt, dwStyle, FALSE, dwExStyle);
if (!(g_hWnd=CreateWindowEx(dwExStyle,
szWindowClass,
szTitle,
dwStyle |
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN,
0, 0,
Rt.right-Rt.left,
Rt.bottom-Rt.top,
NULL,
NULL,
hInst,
NULL)))
{
//如果窗口创建失败,则关闭OpenGL使用的资源,并且弹出一个显示错误的对话框。
glShutdown();
MessageBox(NULL,"Fail to Create Window!","ERROR",MB_OK);
return FALSE;
}
//设置像素格式
static PIXELFORMATDESCRIPTOR pfd=
{
sizeof(PIXELFORMATDESCRIPTOR), //本结构的大小
1, //像素格式描述符的版本号
PFD_DRAW_TO_WINDOW | //该像素格式需要支持窗口
PFD_SUPPORT_OPENGL | //该像素格式需要支持OpenGL
PFD_DOUBLEBUFFER, //需要支持双缓冲
PFD_TYPE_RGBA, //RGBA格式
bits, //像素格式的颜色位数
0, //红色位
0, //RedShift
0, //绿色位
0, //GreenShift
0, //蓝色位
0, //BlueShift
0, //Alpha位
0, //AlphaShift
0, //cAccumBits
0, //cAccumRedBits
0, //cAccumGreenBits
0, //cAccumBlueBits
0, //cAccumAlpha
16, //cDepthBits,16位Z-缓冲
0, //cStencilBits,模板缓冲
0, //cAuxBuffers,辅助缓冲
PFD_MAIN_PLANE, //iLayerType,在主绘图层绘图
0, //保留字节
0, //dwLayerMask
0, //dwVisibleMask
0}; //dwDamageMask
//取得当前窗口的设备描述表DC
g_hDC = GetDC(g_hWnd);
if(!g_hDC) //如果失败则释放OpenGL占用的资源,并返回
{
glShutdown();
MessageBox(NULL,"Fail to get DC from window!","ERROR",MB_OK);
return FALSE;
}
//使用Win32的OpenGL扩展函数选择指定的像素格式
PixelFormat = ChoosePixelFormat(g_hDC, &pfd);
if(!PixelFormat)
{
//如果找不到匹配的像素格式则释放OpenGL占用的资源,并返回
glShutdown();
MessageBox(NULL,"Fail to Choose Pixel Format!","ERROR",MB_OK);
return FALSE;
}
//将设备描述表设置成指定的像素格式
if(!SetPixelFormat(g_hDC,PixelFormat,&pfd))
{
glShutdown();
MessageBox(NULL,"Fail to Set Pixel Format!","ERROR",MB_OK);
return FALSE;
}
//通过扩展函数创建基于取得的设备描述表hDC的渲染描述表hRC。
if (!(g_hRC=wglCreateContext(g_hDC)))
{
glShutdown();
MessageBox(NULL,"Fail to create RC from DC!","ERROR",MB_OK);
return FALSE;
}
//将取得的设备描述表和渲染描述表管理起来
if(!wglMakeCurrent(g_hDC,g_hRC))
{
glShutdown();
MessageBox(NULL,"Fail to link RC to DC","ERROR",MB_OK);
return FALSE;
}
//显示窗口,显示方式是SW_NORMAL
ShowWindow(g_hWnd,SW_SHOW);
SetForegroundWindow(g_hWnd);
SetFocus(g_hWnd);
glResizeScene(width, height); //设置OpenGL的透视方式
//把初始化OpenGL的glInit挪到这里来了
if(!glInit())
{
glShutdown();
MessageBox(NULL,"Can't Init OpenGL!","ERROR",MB_OK);
return FALSE;
}
return TRUE;
}
程序缺省是以窗口方式运行的,可以看到这样一行字符串“Press F1 to Toggle Fullscreen / Windowed Mode”,按F1键就可以在全屏模式和参考模式间切换,如图11-1所示。这个全屏的程序除了显示一行字符串外,什么也不作,但它将作为一个全屏应用的框架,在以后的程序中继续得到使用。