程序结构有待改善,能正常运行,不足之处欢迎指出。
COpenGL.h
#ifndef _COPENGL_H
#define _COPENGL_H
#include "OpenGLFrame.h"
class COpenGL{
private:
HDC m_hDC; //设备描述表
HGLRC m_hRC; //渲染描述表
int m_iWidth;
int m_iHeight;
public:
HWND m_hWnd; //窗口句柄
HINSTANCE m_hInstance; //程序实例
bool m_bFullScreen; //是否全屏显示
bool m_bActive; //是否为活动窗口
bool m_bKeyState[256]; //按键状态
double m_fRotated;
double m_fTranslate;
char m_szWindowClass[32];
char m_szTitle[32];
int m_iBits;
PIXELFORMATDESCRIPTOR m_pfd;
public:
COpenGL();
~COpenGL();
int InitializeGL(void);
int CreateGLWindow(int width, int height, int bits);
int RenderingScene(void);
void SwapBuffers();
int SetPixelFormat(PIXELFORMATDESCRIPTOR * pfd);
int ChangeDisplaySettings(int width, int height, int bits);
void KillWindow(void);
void ResizeScene(GLsizei width, GLsizei height);
};
COpenGL.cpp
#include "COpenGL.h"
extern LRESULT CALLBACK MsgProc(HWND, UINT, WPARAM, LPARAM);
COpenGL::COpenGL()
{
this->m_hWnd = NULL;
this->m_hInstance = NULL;
this->m_hDC = NULL;
this->m_bActive = true;
this->m_bFullScreen = true;
this->m_iBits = 16;
this->m_fRotated = 0.0;
this->m_fTranslate = 0.0;
memset(m_bKeyState, 0, sizeof(bool)*256);
memcpy(m_szWindowClass, "OpenGL", 7);
memcpy(m_szTitle, "OpenGL Frame", 13);
//像素格式 PIXELFORMATDESCRIPTOR
m_pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
m_pfd.nVersion = 1; //版本号
m_pfd.dwFlags = PFD_DRAW_TO_WINDOW | //像素格式支持窗体绘制
PFD_SUPPORT_OPENGL | //像素格式必须支持OpenGL
PFD_DOUBLEBUFFER; //双缓存
m_pfd.iPixelType = PFD_TYPE_RGBA; //RGBA色彩
m_pfd.cColorBits = this->m_iBits; //色深
m_pfd.cRedBits = 0; //忽略色彩位
m_pfd.cRedShift = 0;
m_pfd.cGreenBits = 0;
m_pfd.cGreenShift = 0;
m_pfd.cBlueBits = 0;
m_pfd.cBlueShift = 0; //忽略色彩位
m_pfd.cAlphaBits = 0; //无Alpha缓存
m_pfd.cAlphaShift = 0; //shift bit Ignored
m_pfd.cAccumBits = 0; //无累积缓存
m_pfd.cAccumRedBits = 0; //忽略累积缓存位
m_pfd.cAccumGreenBits = 0; //
m_pfd.cAccumBlueBits = 0; //
m_pfd.cAccumAlphaBits = 0; //忽略累积缓存位
m_pfd.cDepthBits = 16; //16位深度缓存
m_pfd.cStencilBits = 0; //无模板缓存
m_pfd.cAuxBuffers = 0; //无辅助缓存
m_pfd.iLayerType = PFD_MAIN_PLANE; //主图层
m_pfd.bReserved = 0; //保留位
m_pfd.dwLayerMask = 0; //忽略图层掩码
m_pfd.dwVisibleMask = 0; //忽略图层掩码
m_pfd.dwDamageMask = 0; //忽略图层掩码
}
COpenGL::~COpenGL()
{
}
int COpenGL::CreateGLWindow(int width, int height, int bits)
{
m_iHeight = height;
m_iWidth = width;
m_iBits = b
DWORD dwExStyle = 0; //扩展窗体风格
DWORD dwStyle = 0; //窗体风格
WNDCLASS wc;
RECT WindowRect;
WindowRect.left = (long)0;
WindowRect.top = (long)0;
WindowRect.right = (long)width;
WindowRect.bottom = (long)height;
//为窗体获取实例
m_hInstance = ::GetModuleHandle(NULL);
//CS_HREDRAW, CS_VREDRAW表示在横纵方向上改变窗体大小重绘窗体, CS_OWNDC表示窗体自己拥有DC
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)MsgProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = m_hInstance;
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wc.hIcon = ::LoadIcon(NULL, IDI_WINLOGO);
wc.hbrBackground = NULL; //OpenGL函数可以设置
wc.lpszMenuName = NULL;
wc.lpszClassName = m_szWindowClass;
if(!RegisterClass(&wc))
{
MessageBox(NULL, "Failed To Register The Window Class !",
"ERROR", MB_OK | MB_ICONEXCLAMATION);
return 0;
}
if(!this->ChangeDisplaySettings(width, height, bits))
return 0;
if(m_bFullScreen)
{
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP; //pop up 突然出现
ShowCursor(false); //隐藏鼠标
}
else
{
//WS_EX_APPWINDOW最上层窗体位于任务栏上方, WS_EX_WINDOWDGE制定窗体边框突出
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
}
//根据窗体风格调整窗体大小,实际可使用客户区域被覆盖,全屏情况无效
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
//创建窗体
m_hWnd = ::CreateWindowEx(
dwExStyle,
m_szWindowClass,
m_szTitle,
dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0, 0, //窗体位置
WindowRect.right-WindowRect.left,
WindowRect.bottom-WindowRect.top,
NULL,
NULL,
m_hInstance,
NULL);
if(NULL==m_hWnd)
{
this->KillWindow();
MessageBox(NULL, "Window Creation Error !", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return 0;
}
if(NULL == (m_hDC=::GetDC(m_hWnd)))
{
this->KillWindow();
MessageBox(NULL, "Can't Create a GL Device Context !",
"Error", MB_OK | MB_ICONEXCLAMATION);
return 0;
}
if(!this->SetPixelFormat(&m_pfd))
return 0;
//将渲染描述表和设备描述表关联
if(!(m_hRC = wglCreateContext(m_hDC)))
{
this->KillWindow();
MessageBox(NULL, "Can't Create a GL Rendering Context !",
"Error", MB_OK | MB_ICONEXCLAMATION);
return 0;
}
//设置当前渲染描述表
if(!wglMakeCurrent(m_hDC, m_hRC))
{
this->KillWindow();
MessageBox(NULL, "Can't Activate The GL Rendering Context",
"Error", MB_OK | MB_ICONEXCLAMATION);
return 0;
}
//显示窗体
ShowWindow(m_hWnd, SW_SHOW);
SetForegroundWindow(m_hWnd); //提高当前窗体的优先级
SetFocus(m_hWnd); //设置焦点窗体
this->ResizeScene(width, height); //设置OpenGL窗体大小
if(!this->InitializeGL())
{
this->KillWindow();
::MessageBox(NULL, "Failed to Initialize the Window !",
"Error", MB_OK | MB_ICONEXCLAMATION);
return 0;
}
return 1;
}
int COpenGL::InitializeGL()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(1.0); //深度缓存
glShadeModel(GL_SMOOTH); //GL_SMOOTH平滑着色,GL_FLAT恒定着色
glEnable(GL_DEPTH_TEST); //开启深度测试
glDepthFunc(GL_LEQUAL); //GL_LEQUAL 小于等于存储的Z值的定点允许渲染
//设置细节实现的提示,控制OpenGL行为P162
//GL_PERSPECTIVE_CORRECTION_HINT指定透视修订和颜色的插值
//GL_NICEST指定图像质量最好
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
return 1;
}
void COpenGL::ResizeScene(GLsizei width, GLsizei height)
{
if(0 == height)
height = 1;
glViewport(0, 0, width, height); //指定视口
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); //初始化投影矩阵
//设置投影体, 为防止窗口大小改变时图形变形,第二个参数值为视口的宽高比
gluPerspective((GLfloat)45.0, (GLfloat)width/(GLfloat)height,
(GLfloat)1.0, (GLfloat)100.0);
glMatrixMode(GL_MODELVIEW);
}
int COpenGL::RenderingScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清空颜色缓存和深度缓存
glLoadIdentity(); //初始化模型视点矩阵
return 1;
}
void COpenGL::KillWindow(void)
{
if(m_bFullScreen)
{
::ChangeDisplaySettings(NULL, 0); //返回桌面
ShowCursor(true); //显示鼠标
}
if(m_hRC)
{
if(!wglMakeCurrent(NULL, NULL)) //分离RC与DC 测试是否成功分离
{
MessageBox(NULL, "Release of DC and RC Failed !", "Shutdown Error",
MB_OK|MB_ICONINFORMATION);
}
if(!wglDeleteContext(m_hRC)) //释放RC
{
MessageBox(NULL, "Release Rendering Context Failed !", "Shutdown Error",
MB_OK | MB_ICONINFORMATION);
}
m_hRC = NULL;
}
if(m_hDC && !ReleaseDC(m_hWnd, m_hDC)) //&&运算符从左到右,释放DC
{
MessageBox(NULL, "Release Device Context Failed !", "Shutdown Error",
MB_OK | MB_ICONINFORMATION);
m_hDC = NULL;
}
if(m_hWnd && !DestroyWindow(m_hWnd)) //销毁窗口
{
MessageBox(NULL, "Could Not Release hWnd !", "Shutdown Error",
MB_OK | MB_ICONINFORMATION);
m_hWnd = NULL;
}
if(!UnregisterClass(m_szWindowClass, m_hInstance))
{
MessageBox(NULL, "Could Not Unregister Class !", "Shutdown Error",
MB_OK | MB_ICONINFORMATION);
m_hInstance = NULL;
}
}
void COpenGL::SwapBuffers()
{
::SwapBuffers(m_hDC);
}
int COpenGL::ChangeDisplaySettings(int width, int height, int bits)
{
if(m_bFullScreen)
{
DEVMODE dmScreenSettings;
memset(&dmScreenSettings, 0, sizeof(DEVMODE));
dmScreenSettings.dmSize = sizeof(DEVMODE);
dmScreenSettings.dmBitsPerPel = bits; //像素位数
dmScreenSettings.dmPelsWidth = width; //屏幕宽
dmScreenSettings.dmPelsHeight = height; //屏幕高
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if( DISP_CHANGE_SUCCESSFUL != ::ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) ) //切换显示模式
{
if( IDYES == MessageBox(NULL, "The Requested FullScreen Mode Is Not"
"Supported by/nYour Video Card. Use Windowed Mode Instead?",
"My Windows OpenGL Frame", MB_YESNO | MB_ICONEXCLAMATION) )
{
m_bFullScreen = false;
}
else
{
MessageBox(NULL, "Program Will Now Close", "ERROR", MB_OK | MB_ICONSTOP);
return 0;
}
}
}
return 1;
}
int COpenGL::SetPixelFormat(PIXELFORMATDESCRIPTOR * pfd)
{
GLuint PixelFormat = 0;
//像素格式
memcpy(&m_pfd, pfd, sizeof(PIXELFORMATDESCRIPTOR));
//查找是否有合适的像素格式
if(!(PixelFormat = ::ChoosePixelFormat(m_hDC, pfd)))
{
this->KillWindow();
MessageBox(NULL, "Can't Find a Suitable Pixel Format !",
"Error", MB_OK | MB_ICONEXCLAMATION);
return 0;
}
//设置像素格式
if(!::SetPixelFormat(m_hDC, PixelFormat, pfd)) //设置像素格式
{
this->KillWindow();
MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return 0;
}
return 1;
}
COpenGLFrame.h
#ifndef OPENGLFRAME_H
#define OPENGLFRAME_H
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#endif OPENGLFRAME_H
/
COpenGLFrame.cpp
#include "OpenGLFrame.h"
#include "COpenGL.h"
COpenGL theOpenGL;
LRESULT CALLBACK MsgProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
bool done = false;
if(IDNO == MessageBox(NULL, "Would You Like To Run In Fullscreen Mode?", "Start FullScreen ?", MB_YESNO | MB_ICONQUESTION))
theOpenGL.m_bFullScreen = false;
if(!theOpenGL.CreateGLWindow(800, 600, 16))
return 0;
while(!done)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) //是否有等待的消息
{
if(WM_QUIT == msg.message)
done = true;
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
if(theOpenGL.m_bActive)
{
if(theOpenGL.m_bKeyState[VK_ESCAPE]) //如果ESC被按下
done = true;
else //否则更新屏幕图像
{
theOpenGL.RenderingScene();
theOpenGL.SwapBuffers(); //Windows SDK中双缓存交换
}
}
if(theOpenGL.m_bKeyState[VK_F1]) //按F1键切换全屏模式与窗口模式
{
theOpenGL.m_bKeyState[VK_F1] = false;
theOpenGL.KillWindow(); //关闭当前窗体
theOpenGL.m_bFullScreen = !theOpenGL.m_bFullScreen;
//切换模式重新生成窗体
if(!theOpenGL.CreateGLWindow(800, 600, 16))
return 0;
}
}
}
//done = true 关闭程序,退出
theOpenGL.KillWindow();
return (msg.wParam);
}
//消息处理函数
LRESULT CALLBACK MsgProc( HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam )
{
switch(uMsg)
{
case WM_ACTIVATE: //查看窗口活动状态
if(!HIWORD(wParam)) //检查最小化情况
theOpenGL.m_bActive = true;
else
theOpenGL.m_bActive = false;
return 0;
case WM_SYSCOMMAND: //截取系统消息
switch(wParam)
{
case SC_SCREENSAVE: //屏幕保护启动
case SC_MONITORPOWER: //监视器转换为节电模式
return 0; //组织发生
}
break;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_KEYDOWN: //WM_KEYDOWN, WM_KEYUP消息,wParam包含按键ASCII码
theOpenGL.m_bKeyState[wParam] = true; //按下键,设置该键状态为按下
return 0;
case WM_KEYUP:
theOpenGL.m_bKeyState[wParam] = false;
return 0;
case WM_SIZE: //WM_SIZE消息的lParam低位为窗口宽, 高位为窗口高
theOpenGL.ResizeScene(LOWORD(lParam), HIWORD(lParam));
return 0;
}
//处理其余消息
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}