Window OpenGL 程式C++版本

來源:互聯網
上載者:User

程式結構有待改善,能正常運行,不足之處歡迎指出。

////////////////////////////////////////////////////////////////////////////////////

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);
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.