5, 在OnCreate中我们将通过建立像素格式和绘制上下文来初始化OpenGL. 在InitializeOpenGL()中会创建一个设备上下文(DC),为这个DC选择一个像素格式,创建和这个DC相关的绘制上下文(RC),然后选择这个RC.这个函数会调用SetupPixelFormat()来建立像素格式。
int CCY457OpenGLView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
//Initialize OpenGL Here
InitializeOpenGL();
return 0;
}
BOOL CCY457OpenGLView::InitializeOpenGL()
{
//Get a DC for the Client Area
m_pDC = new CClientDC(this);
//Failure to Get DC
if(m_pDC == NULL)
{
MessageBox("Error Obtaining DC");
return FALSE;
}
//Failure to set the pixel format
if(!SetupPixelFormat())
{
return FALSE;
}
//Create Rendering Context
m_hRC = ::wglCreateContext (m_pDC->GetSafeHdc ());
//Failure to Create Rendering Context
if(m_hRC == 0)
{
MessageBox("Error Creating RC");
return FALSE;
}
//Make the RC Current
if(::wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC)==FALSE)
{
MessageBox("Error making RC Current");
return FALSE;
}
//Specify Black as the clear color
::glClearColor(0.0f,0.0f,0.0f,0.0f);
//Specify the back of the buffer as clear depth
::glClearDepth(1.0f);
//Enable Depth Testing
::glEnable(GL_DEPTH_TEST);
return TRUE;
}
//Setup Pixel Format
/////////////////////////////////////////////////////////////////////////////
BOOL CCY457OpenGLView::SetupPixelFormat()
{
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit 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, // accum bits ignored
16, // 16-bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int m_nPixelFormat = ::ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);
if ( m_nPixelFormat == 0 )
{
return FALSE;
}
if ( ::SetPixelFormat(m_pDC->GetSafeHdc(), m_nPixelFormat, &pfd) == FALSE)
{
return FALSE;
}
return TRUE;
}
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
//Initialize OpenGL Here
InitializeOpenGL();
return 0;
}
BOOL CCY457OpenGLView::InitializeOpenGL()
{
//Get a DC for the Client Area
m_pDC = new CClientDC(this);
//Failure to Get DC
if(m_pDC == NULL)
{
MessageBox("Error Obtaining DC");
return FALSE;
}
//Failure to set the pixel format
if(!SetupPixelFormat())
{
return FALSE;
}
//Create Rendering Context
m_hRC = ::wglCreateContext (m_pDC->GetSafeHdc ());
//Failure to Create Rendering Context
if(m_hRC == 0)
{
MessageBox("Error Creating RC");
return FALSE;
}
//Make the RC Current
if(::wglMakeCurrent (m_pDC->GetSafeHdc (), m_hRC)==FALSE)
{
MessageBox("Error making RC Current");
return FALSE;
}
//Specify Black as the clear color
::glClearColor(0.0f,0.0f,0.0f,0.0f);
//Specify the back of the buffer as clear depth
::glClearDepth(1.0f);
//Enable Depth Testing
::glEnable(GL_DEPTH_TEST);
return TRUE;
}
//Setup Pixel Format
/////////////////////////////////////////////////////////////////////////////
BOOL CCY457OpenGLView::SetupPixelFormat()
{
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit 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, // accum bits ignored
16, // 16-bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int m_nPixelFormat = ::ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);
if ( m_nPixelFormat == 0 )
{
return FALSE;
}
if ( ::SetPixelFormat(m_pDC->GetSafeHdc(), m_nPixelFormat, &pfd) == FALSE)
{
return FALSE;
}
return TRUE;
}
6, 在OnSize()中一般用来设置视口和视锥,因为这些是和窗口大小相关的。基本操作包括设置视口,选择投影矩阵,设置模型视图矩阵。
void CCY457OpenGLView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
GLdouble aspect_ratio; // width/height ratio
if ( 0 >= cx || 0 >= cy )
{
return;
}
// select the full client area
::glViewport(0, 0, cx, cy);
// compute the aspect ratio
// this will keep all dimension scales equal
aspect_ratio = (GLdouble)cx/(GLdouble)cy;
// select the projection matrix and clear it
::glMatrixMode(GL_PROJECTION);
::glLoadIdentity();
// select the viewing volume
::gluPerspective(45.0f, aspect_ratio, .01f, 200.0f);
// switch back to the modelview matrix and clear it
::glMatrixMode(GL_MODELVIEW);
::glLoadIdentity();
}
{
CView::OnSize(nType, cx, cy);
GLdouble aspect_ratio; // width/height ratio
if ( 0 >= cx || 0 >= cy )
{
return;
}
// select the full client area
::glViewport(0, 0, cx, cy);
// compute the aspect ratio
// this will keep all dimension scales equal
aspect_ratio = (GLdouble)cx/(GLdouble)cy;
// select the projection matrix and clear it
::glMatrixMode(GL_PROJECTION);
::glLoadIdentity();
// select the viewing volume
::gluPerspective(45.0f, aspect_ratio, .01f, 200.0f);
// switch back to the modelview matrix and clear it
::glMatrixMode(GL_MODELVIEW);
::glLoadIdentity();
}
7,在绘制场景时,一般包括如下步骤:1)清空缓存。2)绘制场景。3)Flush掉渲染流水线。4)若设置了双缓冲,则交换前后台缓冲区。
void CCY457OpenGLView::OnDraw(CDC* pDC)
{
CCY457OpenGLDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// Clear out the color & depth buffers
::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
RenderScene();
// Tell OpenGL to flush its pipeline
::glFlush();
// Now Swap the buffers
::SwapBuffers( m_pDC->GetSafeHdc() );
}
void CCY457OpenGLView::RenderScene ()
{//第一个玩具嘛,先空着,后面慢慢填
}
{
CCY457OpenGLDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// Clear out the color & depth buffers
::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
RenderScene();
// Tell OpenGL to flush its pipeline
::glFlush();
// Now Swap the buffers
::SwapBuffers( m_pDC->GetSafeHdc() );
}
void CCY457OpenGLView::RenderScene ()
{//第一个玩具嘛,先空着,后面慢慢填
}
8,试试改变窗口的大小,你会看到很严重的闪烁,并且关闭程序后会报告内存泄露,因此我们这就来解决这两个问题吧。
发生闪烁的原因是Windows先绘制背景,然后再是OpenGL绘制,因为我们已经让OpenGL负责清空背景色,因此我们不需要Windows去清空背景了
BOOL CCY457OpenGLView::OnEraseBkgnd(CDC* pDC)
{
//Tell Windows not to erase the background
return TRUE;
}
{
//Tell Windows not to erase the background
return TRUE;
}
内存泄露的原因是我们在SetupPixelFormat()中使用了new运算符来为CClientDC对象分配内存,因此需要显式delete掉。
void CCY457OpenGLView::OnDestroy()
{
CView::OnDestroy();
//Make the RC non-current
if(::wglMakeCurrent (NULL, NULL) == FALSE)
{
MessageBox("Could not make RC non-current");
}
//Delete the rendering context
if(::wglDeleteContext (m_hRC)==FALSE)
{
MessageBox("Could not delete RC");
}
//Delete the DC
if(m_pDC)
{
delete m_pDC;
}
//Set it to NULL
m_pDC = NULL;
}
{
CView::OnDestroy();
//Make the RC non-current
if(::wglMakeCurrent (NULL, NULL) == FALSE)
{
MessageBox("Could not make RC non-current");
}
//Delete the rendering context
if(::wglDeleteContext (m_hRC)==FALSE)
{
MessageBox("Could not delete RC");
}
//Delete the DC
if(m_pDC)
{
delete m_pDC;
}
//Set it to NULL
m_pDC = NULL;
}