今天写了个基于MFC对话框的OpenGL类:COpenGL,可以在对话框程序中使用OpenGL了,并且提供了全屏与非全屏转换的两个函数,很容易使用,速度快。可以到这里下载demo project。有什么意见或问题,请大家给我留言。:)
使用方法:在对话框上加一个Static控件(或者其他的也可以),在OnInitDialog()中加人下面这段代码(假设控件ID为IDC_OPENGL,m_openGL是类COpenGL的对象):
CRect rect;
GetDlgItem(IDC_OPENGL)->GetWindowRect(rect);
ScreenToClient(rect);
m_openGL.Create(rect, this);
然后在适当的地方调用m_openGL.RenderGLScene()就可以了。
以下是类代码(OpenGL.h和OpenGL.cpp):
#if !defined(AFX_OPENGL_H__38B5D1C8_2DFF_4A7D_9A99_3AC401C19D72__INCLUDED_)
#define AFX_OPENGL_H__38B5D1C8_2DFF_4A7D_9A99_3AC401C19D72__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// OpenGL.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// COpenGL window
class COpenGL : public CWnd
{
// Construction
public:
COpenGL();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(COpenGL)
//}}AFX_VIRTUAL
// Implementation
public:
BOOL SetNormScreen();
BOOL SetFullScreen(int width, int height, int depth);
virtual void RenderGLScene();
void Create(CRect rect, CWnd *parent);
virtual ~COpenGL();
// Generated message map functions
protected:
CRect m_rect;
CWnd* m_parent;
BOOL m_bFullScreen;
DEVMODE m_DMsaved;
BOOL m_bInit;
int InitGL();
void KillGLWindow();
HDC m_hDC;
HGLRC m_hRC;
//{{AFX_MSG(COpenGL)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnPaint();
afx_msg void OnSize(UINT nType, int cx, int cy);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_OPENGL_H__38B5D1C8_2DFF_4A7D_9A99_3AC401C19D72__INCLUDED_)
// OpenGL.cpp : implementation file
//
#include "stdafx.h"
#include "DialogOpenGL.h"
#include "OpenGL.h"
#include <gl/gl.h>
#include <gl/glu.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// COpenGL
COpenGL::COpenGL():m_bInit(FALSE),m_bFullScreen(FALSE),
m_hDC(NULL),m_hRC(NULL),m_parent(NULL)
{
}
COpenGL::~COpenGL()
{
KillGLWindow(); // Shutdown
}
BEGIN_MESSAGE_MAP(COpenGL, CWnd)
//{{AFX_MSG_MAP(COpenGL)
ON_WM_CREATE()
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_KEYDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// COpenGL message handlers
void COpenGL::Create(CRect rect, CWnd *parent)
{
if (m_bInit) return;
ASSERT(rect);
ASSERT(parent);
m_rect = rect;
m_parent = parent;
CString className = AfxRegisterWndClass(
CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
NULL,
(HBRUSH)GetStockObject(BLACK_BRUSH),
NULL);
CreateEx(
0,
className,
"OpenGL",
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
rect,
parent,
0);
}
int COpenGL::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &m_DMsaved);
GLuint PixelFormat; // Holds The Results After Searching For A Match
static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
m_DMsaved.dmBitsPerPel, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
if ( !( m_hDC = ::GetDC ( m_hWnd ) ) ) { // Did We Get A Device Context?
KillGLWindow (); // Reset The Display
TRACE ( "Can't Create A GL Device Context." );
return FALSE;
}
if ( !( PixelFormat = ChoosePixelFormat ( m_hDC, &pfd ) ) ) { // Did Windows Find A Matching Pixel Format?
KillGLWindow (); // Reset The Display
TRACE ( "Can't Find A Suitable PixelFormat." );
return FALSE;
}
if ( !SetPixelFormat ( m_hDC, PixelFormat, &pfd ) ){ // Are We Able To Set The Pixel Format?
KillGLWindow (); // Reset The Display
TRACE ( "Can't Set The PixelFormat." );
return FALSE;
}
if ( !( m_hRC = wglCreateContext ( m_hDC ) ) ) { // Are We Able To Get A Rendering Context?
KillGLWindow (); // Reset The Display
TRACE( " Can't Create A GL Rendering Context." );
return FALSE;
}
if ( !wglMakeCurrent ( m_hDC, m_hRC ) ) { // Try To Activate The Rendering Context
KillGLWindow (); // Reset The Display
TRACE ( "Can't Activate The GL Rendering Context." );
return FALSE;
}
if ( !InitGL () ) { // Initialize Our Newly Created GL Window
KillGLWindow (); // Reset The Display
TRACE ( "Initialization Failed." );
return FALSE;
}
m_bInit = TRUE;
return 0;
}
void COpenGL::KillGLWindow()
{
if (m_bFullScreen) // Are We In Fullscreen Mode?
{
if (!ChangeDisplaySettings(NULL,CDS_TEST)) { // if the shortcut doesn't work
ChangeDisplaySettings(NULL,CDS_RESET); // Do it anyway (to get the values out of the registry)
ChangeDisplaySettings(&m_DMsaved,CDS_RESET); // change it to the saved settings
} else {
ChangeDisplaySettings(NULL,CDS_RESET);
}
ShowCursor(TRUE); // Show Mouse Pointer
}
if ( m_hRC ) { // Do We Have A Rendering Context?
if ( !wglMakeCurrent ( NULL, NULL ) ) { // Are We Able To Release The DC And RC Contexts?
TRACE ( "Release Of DC And RC Failed." );
}
if ( !wglDeleteContext ( m_hRC ) ) { // Are We Able To Delete The RC?
TRACE ( "Release Rendering Context Failed." );
}
m_hRC = NULL; // Set RC To NULL
}
if ( m_hDC && !::ReleaseDC ( m_hWnd, m_hDC ) ) { // Are We Able To Release The DC
TRACE ( "Release Device Context Failed." );
m_hDC = NULL; // Set DC To NULL
}
if ( m_hWnd && !::DestroyWindow ( m_hWnd ) ) { // Are We Able To Destroy The Window?
TRACE( "Could Not Release m_hWnd." );
m_hWnd = NULL; // Set m_hWnd To NULL
}
}
int COpenGL::InitGL()
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
return TRUE; // Initialization Went OK
}
void COpenGL::RenderGLScene()
{
if(!m_bInit) return;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity();
// EXAMPLE OPENGL CODE START ////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
static GLfloat xrot; // X Rotation
static GLfloat yrot; // Y Rotation
static GLfloat zrot; // Z Rotation
glPushMatrix(); // Push Matrix Onto Stack (Copy The Current Matrix)
glLoadIdentity(); // Reset The Current Modelview Matrix
glTranslatef(0.0f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
glRotatef(zrot,0.0f,0.0f,1.0f);
glBegin(GL_QUADS);
// Front Face
glColor3f(1.0f,0.0f,0.0f);glVertex3f(-1.0f, -1.0f, 1.0f);
glColor3f(0.0f,1.0f,0.0f);glVertex3f( 1.0f, -1.0f, 1.0f);
glColor3f(0.0f,1.0f,0.0f);glVertex3f( 1.0f, 1.0f, 1.0f);
glColor3f(0.0f,0.0f,1.0f);glVertex3f(-1.0f, 1.0f, 1.0f);
// Back Face
glColor3f(1.0f,0.0f,0.0f);glVertex3f(-1.0f, -1.0f, -1.0f);
glColor3f(0.0f,1.0f,0.0f);glVertex3f(-1.0f, 1.0f, -1.0f);
glColor3f(0.0f,1.0f,0.0f);glVertex3f( 1.0f, 1.0f, -1.0f);
glColor3f(0.0f,0.0f,1.0f);glVertex3f( 1.0f, -1.0f, -1.0f);
// Top Face
glColor3f(0.0f,1.0f,0.0f);glVertex3f(-1.0f, 1.0f, -1.0f);
glColor3f(0.0f,0.0f,1.0f);glVertex3f(-1.0f, 1.0f, 1.0f);
glColor3f(0.0f,1.0f,0.0f);glVertex3f( 1.0f, 1.0f, 1.0f);
glColor3f(0.0f,1.0f,0.0f);glVertex3f( 1.0f, 1.0f, -1.0f);
// Bottom Face
glColor3f(1.0f,0.0f,0.0f);glVertex3f(-1.0f, -1.0f, -1.0f);
glColor3f(0.0f,0.0f,1.0f);glVertex3f( 1.0f, -1.0f, -1.0f);
glColor3f(0.0f,1.0f,0.0f);glVertex3f( 1.0f, -1.0f, 1.0f);
glColor3f(1.0f,0.0f,0.0f);glVertex3f(-1.0f, -1.0f, 1.0f);
// Right face
glColor3f(0.0f,0.0f,1.0f);glVertex3f( 1.0f, -1.0f, -1.0f);
glColor3f(0.0f,1.0f,0.0f);glVertex3f( 1.0f, 1.0f, -1.0f);
glColor3f(0.0f,1.0f,0.0f);glVertex3f( 1.0f, 1.0f, 1.0f);
glColor3f(0.0f,1.0f,0.0f);glVertex3f( 1.0f, -1.0f, 1.0f);
// Left Face
glColor3f(1.0f,0.0f,0.0f);glVertex3f(-1.0f, -1.0f, -1.0f);
glColor3f(1.0f,0.0f,0.0f);glVertex3f(-1.0f, -1.0f, 1.0f);
glColor3f(0.0f,0.0f,1.0f);glVertex3f(-1.0f, 1.0f, 1.0f);
glColor3f(0.0f,1.0f,0.0f);glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
glPopMatrix(); // Pop Matrix Off The Stack
xrot+=1.3f;
yrot+=1.2f;
zrot+=1.4f; // Decrease The Rotation Variable For The Quad
//////////////////////////////////////////////////////////////////////////////
// EXAMPLE OPENGL CODE END //////////////////////////////////////////////////////////
// Swap our scene to the front
SwapBuffers(m_hDC);
Invalidate(FALSE);
}
void COpenGL::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
::ValidateRect ( m_hWnd, NULL );
// Do not call CWnd::OnPaint() for painting messages
}
void COpenGL::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
if ( cy==0) { // Prevent A Divide By Zero By
cy=1; // Making Height Equal One
}
glViewport(0,0,cx,cy); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
gluPerspective(45.0f,(GLfloat)cx/(GLfloat)cy,0.1f,100.0f); // Calculate The Aspect Ratio Of The Window
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
BOOL COpenGL::SetFullScreen(int width, int height, int depth)
{
if(!m_bInit) return FALSE;
if (m_bFullScreen) return TRUE;
DEVMODE dmScreenSettings; // Device Mode
memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared
dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Size Of The Devmode Structure
dmScreenSettings.dmPelsWidth = width; // Selected Screen Width
dmScreenSettings.dmPelsHeight = height; // Selected Screen Height
dmScreenSettings.dmBitsPerPel = depth; // Selected Bits Per Pixel
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
// Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{
return m_bFullScreen = FALSE;
}
SetParent(NULL);
SetWindowPos(&CWnd::wndTop,
0, 0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN),
SWP_SHOWWINDOW);
ShowCursor(FALSE);
SetFocus();
return m_bFullScreen = TRUE;
}
BOOL COpenGL::SetNormScreen()
{
if(!m_bInit) return FALSE;
if (m_bFullScreen) // Are We In Fullscreen Mode?
{
if (!ChangeDisplaySettings(NULL,CDS_TEST)) { // if the shortcut doesn't work
ChangeDisplaySettings(NULL,CDS_RESET); // Do it anyway (to get the values out of the registry)
ChangeDisplaySettings(&m_DMsaved,CDS_RESET); // change it to the saved settings
} else {
ChangeDisplaySettings(NULL,CDS_RESET);
}
SetParent(m_parent);
SetWindowPos(&CWnd::wndTop,
m_rect.left, m_rect.top,
m_rect.Width(),
m_rect.Height(),
SWP_SHOWWINDOW);
ShowCursor(TRUE); // Show Mouse Pointer
m_bFullScreen = FALSE;
}
return TRUE;
}