程式結構有待改善,能正常運行,不足之處歡迎指出。
////////////////////////////////////////////////////////////////////////////////////
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);
}