1. 程式人生 > >MFC對話方塊程式中使用OpenGL

MFC對話方塊程式中使用OpenGL

        在MFC的對話方塊程式中需要使用OpenGL在某個對話方塊中作圖,綜合了網上的兩篇文章的內容(文章一文章二),也有自己的心得體會。

        首先需要配置好opengl的環境,程式中會使用到glaux中的庫和函式,這裡將它的lib,h,dll檔案的下載連結附上。其他的庫windows中好像帶有。

        先將對OpenGL的操作封裝成一個類,這是第一篇文章的主要思想:

標頭檔案OpenGL.h

#pragma once
#include <gl/GL.h>
#include <gl/GLU.h>
#include <GLAUX.H>

class COpenGL
{
public:
	COpenGL(void);
	~COpenGL(void);
	HDC hDC;
	HGLRC hRC;

public:
	/************************************************************************/
	/*    對OpenGL的一些初始化工作,width和height表示視窗的寬和高                                                                  */
	/************************************************************************/
	void Init(int width,int height);

	/************************************************************************/
	/* 設定畫素格式                                                                     */
	/************************************************************************/
	bool SetupPixelFormat(HDC hDC0);

	/************************************************************************/
	/* 視窗大小改變時的回撥函式                                                                     */
	/************************************************************************/
	void Reshap(int width,int height);

	/************************************************************************/
	/*  具體的渲染操作,視窗中顯示的內容是在這個函式中完成的                                                                    */
	/************************************************************************/
	void Render();
};

原始檔OpenGL.cpp
#include "StdAfx.h"
#include "OpenGL.h"

COpenGL::COpenGL(void)
{
}

COpenGL::~COpenGL(void)
{
	wglMakeCurrent(hDC,NULL);
	wglDeleteContext(hRC);
}

void COpenGL::Init(int width,int height){
	// openGL的初始化設定
	glClearColor(0.0, 1.0, 1.0, 0.0);
	glShadeModel(GL_SMOOTH);
	//glViewport(0, 0, 200, 200);
	glMatrixMode(GL_PROJECTION);
	gluPerspective(60, (GLfloat)width/(GLfloat)height, 0.1, 100.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

bool COpenGL::SetupPixelFormat(HDC hDC0){
	int nPixelFormat;                 // 象素點格式
	hDC=hDC0;
	PIXELFORMATDESCRIPTOR pfd = {
		sizeof(PIXELFORMATDESCRIPTOR),    // pfd結構的大小
		1,                                // 版本號
		PFD_DRAW_TO_WINDOW |              // 支援在視窗中繪圖
		PFD_SUPPORT_OPENGL |              // 支援OpenGL
		PFD_DOUBLEBUFFER,                 // 雙快取模式
		PFD_TYPE_RGBA,                    // RGBA 顏色模式
		24,                               // 24 位顏色深度
		0, 0, 0, 0, 0, 0,                 // 忽略顏色位
		0,                                // 沒有非透明度快取
		0,                                // 忽略移位位
		0,                                // 無累加快取
		0, 0, 0, 0,                       // 忽略累加位
		32,                               // 32 位深度快取   
		0,                                // 無模板快取
		0,                                // 無輔助快取
		PFD_MAIN_PLANE,                   // 主層
		0,                                // 保留
		0, 0, 0                           // 忽略層,可見性和損毀掩模
	};
	if (!(nPixelFormat = ChoosePixelFormat(hDC, &pfd)))
	{ MessageBox(NULL,L"can not find proper mode",L"Error",MB_OK|MB_ICONEXCLAMATION);
	return FALSE;
	}
	SetPixelFormat(hDC,nPixelFormat,&pfd);
	hRC = wglCreateContext(hDC);         
	wglMakeCurrent(hDC, hRC);            
	return TRUE;
}
void COpenGL::Reshap(int width,int height){
	glViewport(0,0,width,height);         
	glMatrixMode(GL_PROJECTION);          
	glLoadIdentity();                 
	gluPerspective                        
		( 60.0f,                       
		(GLfloat)width/(GLfloat)height,
		0.1f,                      
		100.0f                     
		); 
	//gluLookAt(10,5,10,0,0,0,0,1,0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}
void COpenGL::Render(){
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0, 0.0, 0.0);
	glLoadIdentity();
	glTranslatef(0.0, 0.0, -5.0);
	glBegin(GL_TRIANGLES);
	glVertex3f(0.0, 1.0, 0.0);
	glVertex3f(-1.0, -1.0, 0.0);
	glVertex3f(1.0, -1.0, 0.0);
	glEnd();
	SwapBuffers(hDC);    
}

         上面將對OpenGL的操作封裝成了一個工具類,但是照第一篇文章的思路實現時由於我的工程是基於MFC的對話方塊程式,照他上面說的方法顯示出的對話方塊中沒有東西。於是使用這個工具類時參照了第二篇文章的方法,也明白瞭如何在其他的工程中使用這個工具類。

      具體的方法是:

1.在需要繪圖的視窗類中新增OpenGL.h標頭檔案,並宣告一個COpenGL型別的成員變數。如我想在CDialog4這個類中使用OpenGL繪圖,那麼在它 的標頭檔案中包含OpenGL.h,並宣告一個COpenGL型別的成員變數。

2.新增兩個訊息響應函式,即WM_SIZE和WM_TIMER訊息的處理,重寫一個函式OnInitDialog。

這兩步操作完成後,CDialog4的標頭檔案如下:

#pragma once
#include "OpenGL.h"

// CDialog4 對話方塊

class CDialog4 : public CDialog
{
	DECLARE_DYNAMIC(CDialog4)
public:
	COpenGL openGL;

public:
	CDialog4(CWnd* pParent = NULL);   // 標準建構函式
	virtual ~CDialog4();

// 對話方塊資料
	enum { IDD = IDD_DIALOG4 };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支援

	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnSize(UINT nType, int cx, int cy);
	virtual BOOL OnInitDialog();
	afx_msg void OnTimer(UINT_PTR nIDEvent);
};

CDialog4的原始檔如下:
// Dialog4.cpp : 實現檔案
//

#include "stdafx.h"
#include "ComputerGraphic.h"
#include "Dialog4.h"


// CDialog4 對話方塊

IMPLEMENT_DYNAMIC(CDialog4, CDialog)

CDialog4::CDialog4(CWnd* pParent /*=NULL*/)
	: CDialog(CDialog4::IDD, pParent)
{

}

CDialog4::~CDialog4()
{
}

void CDialog4::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CDialog4, CDialog)
	ON_WM_SIZE()
	ON_WM_TIMER()
END_MESSAGE_MAP()




void CDialog4::OnSize(UINT nType, int cx, int cy)
{
	CDialog::OnSize(nType, cx, cy);
	openGL.Reshap(cx,cy);
}

BOOL CDialog4::OnInitDialog()
{
	CDialog::OnInitDialog();

	/************************************************************************/
	/*  傳遞給SetupPixelFormat的引數是要繪圖的物件的DC,可以是視窗中的某一個控制元件
	這裡使用的是視窗的DC,即在視窗中繪圖,而不是在視窗的某個控制元件中繪圖*/
	/************************************************************************/
	openGL.SetupPixelFormat(::GetDC(m_hWnd));

	//得到繪圖區域對應的長方形
	CRect rect;
	GetClientRect(&rect);

	//設定繪圖區域的寬和高
	openGL.Init(rect.right,rect.bottom);
	SetTimer(1,10,0);
	

	return TRUE;  // return TRUE unless you set the focus to a control
	// 異常: OCX 屬性頁應返回 FALSE
}

void CDialog4::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此新增訊息處理程式程式碼和/或呼叫預設值
	openGL.Render();
	CDialog::OnTimer(nIDEvent);
}

        重點是在OnInitDialog中的函式呼叫,獲取不同控制元件的DC就可以在不同的控制元件中繪圖了。這時使用該方法就很靈活方便了。OnSize函式是在視窗改變時重新設定透視投影的寬和高,如果沒有這個訊息處理當視窗大小改變時圖形的位置不會變化,看起來就會很奇怪。

       程式執行後的效果如下圖: