具有两个OpenGL图形视图的MFC MDI拆分器无法工作

MFC MDI splitter with two OpenGL graphics views are not working

本文关键字:MDI MFC 拆分 工作 视图 图形 OpenGL 两个      更新时间:2023-10-16

我想创建一个应用程序,其中应用程序视图将与OpenGL三维模型在两个不同的视图中进行分割,并使用拆分器连接到子框架。为此,我制作了一个从视图类扩展而来的父类,在这个类中,我初始化了所有opengl所需的代码。

例如

#pragma once
#include <gl/gl.h>
#include <gl/glu.h>
#define IL   //when you dont want to use image library and you want to load everything by your self then remove this
// COpenGlView view
class COpenGlView : public CView
{
DECLARE_DYNCREATE(COpenGlView)
protected:
void oglBeginRendering();
COpenGlView();           // protected constructor used by dynamic creation
virtual ~COpenGlView();
/*******************/
/* Private Members */
/*******************/
// Window information
CWnd  *hWnd;
HDC   hdc;          
HGLRC hrc;          
int   m_nPixelFormat;
CRect m_rect;
CRect m_oldWindow;
CRect m_originalRect;
public:
/******************/
/* Public Members */
/******************/
UINT_PTR m_unpTimer;
// View information variables
float    m_fLastX;
float    m_fLastY;
float    m_fPosX;
float    m_fPosY;
float    m_fZoom;
float    m_fRotX;
float    m_fRotY;
bool     m_bIsMaximized;
float    m_fZoomSpeed;
float    m_fRotateSpeed;
GLuint texture[1];

void oglCreate(CRect rect, CWnd *parent,CString strWindowName=L"OpenGl");
virtual void oglInitialize(void);
virtual void oglDrawScene(void);
float   randFloat(const float& min, const float& max);
int     randInt(const int& min, const int& max);
void Reset();

virtual void OnDraw(CDC* pDC);      // overridden to draw this view
#ifdef _DEBUG
virtual void AssertValid() const;
#ifndef _WIN32_WCE
virtual void Dump(CDumpContext& dc) const;
#endif
#endif
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnPaint();
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnTimer(UINT_PTR nIDEvent);
virtual void OnInitialUpdate();
};

这是cpp

// OpenGlView.cpp : implementation file
//
#include "stdafx.h"
#include "OpenGlView.h"

// COpenGlView
IMPLEMENT_DYNCREATE(COpenGlView, CView)
COpenGlView::COpenGlView()
{
m_fPosX = 0.0f;     // X position of model in camera view
m_fPosY = 0.0f;     // Y position of model in camera view
m_fZoom = 5.0f; // Zoom on model in camera view
m_fRotX = 0.0f;     // Rotation on model in camera view
m_fRotY = 0.0f;     // Rotation on model in camera view
m_fZoomSpeed=0.05f;
m_fRotateSpeed = 0.05f;
m_bIsMaximized = false;
}
COpenGlView::~COpenGlView()
{
}
void COpenGlView::Reset()
{
m_fPosX = 0.0f;     // X position of model in camera view
m_fPosY = 0.0f;     // Y position of model in camera view
m_fZoom = 5.0f; // Zoom on model in camera view
m_fRotX = 0.0f;     // Rotation on model in camera view
m_fRotY = 0.0f;     // Rotation on model in camera view
m_fZoomSpeed=0.05f;
m_fRotateSpeed = 0.05f;
m_bIsMaximized = false;
}
BEGIN_MESSAGE_MAP(COpenGlView, CView)
ON_WM_CREATE()
ON_WM_PAINT()
ON_WM_MOUSEMOVE()
ON_WM_SIZE()
ON_WM_TIMER()
END_MESSAGE_MAP()

// COpenGlView drawing
void COpenGlView::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
// TODO: add draw code here
}

// COpenGlView diagnostics
#ifdef _DEBUG
void COpenGlView::AssertValid() const
{
CView::AssertValid();
}
#ifndef _WIN32_WCE
void COpenGlView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
#endif
#endif //_DEBUG

// COpenGlView message handlers
int COpenGlView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;

return 0;
}
void COpenGlView::OnPaint()
{
//CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CView::OnPaint() for painting messages
ValidateRect(NULL);
}
void COpenGlView::OnMouseMove(UINT nFlags, CPoint point)
{
int diffX = (int)(point.x - m_fLastX);
int diffY = (int)(point.y - m_fLastY);
m_fLastX  = (float)point.x;
m_fLastY  = (float)point.y;

// Left mouse button
if (nFlags & MK_LBUTTON)
{
m_fRotX += (float)m_fRotateSpeed * diffY;
if ((m_fRotX > 360.0f) || (m_fRotX < -360.0f))
{
m_fRotX = 0.0f;
}
m_fRotY += (float)0.5f * diffX;
if ((m_fRotY > 360.0f) || (m_fRotY < -360.0f))
{
m_fRotY = 0.0f;
}
}
// Right mouse button
else if (nFlags & MK_RBUTTON)
{
m_fZoom -= (float)m_fZoomSpeed * diffY;
}
// Middle mouse button
else if (nFlags & MK_MBUTTON)
{
m_fPosX += (float)0.05f * diffX;
m_fPosY -= (float)0.05f * diffY;
}

OnDraw(NULL);

CView::OnMouseMove(nFlags, point);
}
void COpenGlView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
if (0 >= cx || 0 >= cy || nType == SIZE_MINIMIZED) return;
// Map the OpenGL coordinates.
glViewport(0, 0, cx, cy);
// Projection view
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set our current view perspective
gluPerspective(35.0f, (float)cx / (float)cy, 0.01f, 2000.0f);
// Model view
glMatrixMode(GL_MODELVIEW);
switch (nType)
{
// If window resize token is "maximize"
case SIZE_MAXIMIZED:
{
// Get the current window rect
GetWindowRect(m_rect);
// Move the window accordingly
MoveWindow(6, 6, cx - 14, cy - 14);
// Get the new window rect
GetWindowRect(m_rect);
// Store our old window as the new rect
m_oldWindow = m_rect;
break;
}
// If window resize token is "restore"
case SIZE_RESTORED:
{
// If the window is currently maximized
if (m_bIsMaximized)
{
// Get the current window rect
GetWindowRect(m_rect);
// Move the window accordingly (to our stored old window)
MoveWindow(m_oldWindow.left, m_oldWindow.top - 18, m_originalRect.Width() - 4, m_originalRect.Height() - 4);
// Get the new window rect
GetWindowRect(m_rect);
// Store our old window as the new rect
m_oldWindow = m_rect;
}
break;
}
}
}

void COpenGlView::oglBeginRendering()
{
SetTimer(1, 1, 0);
}
void COpenGlView::OnTimer(UINT_PTR nIDEvent)
{
switch (nIDEvent)
{
case 1:
{
// Clear color and depth buffer bits
wglMakeCurrent(hdc, hrc);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw OpenGL scene
oglDrawScene();
// Swap buffers
SwapBuffers(hdc);
glFlush();
wglMakeCurrent(NULL, NULL);

break;
}
default:
break;
}

CView::OnTimer(nIDEvent);
}
void COpenGlView::OnInitialUpdate()
{
CView::OnInitialUpdate();
COpenGlView::oglInitialize();
// TODO: Add your specialized code here and/or call the base class
}

void COpenGlView::oglCreate(CRect rect, CWnd *parent,CString strWindowName)
{
CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_OWNDC, NULL, (HBRUSH)GetStockObject(BLACK_BRUSH), NULL);
CreateEx(0, className,strWindowName, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, rect, parent, 0);
// Set initial variables' values
m_oldWindow    = rect;
m_originalRect = rect;
hWnd = parent;
GLenum s = glGetError();
}
void COpenGlView::oglInitialize(void)
{
// Initial Setup:
//
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
32, // bit depth
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16, // z-buffer depth
0, 0, 0, 0, 0, 0, 0,
};

// Get device context only once.
//hdc = GetDC()->m_hDC;
// Pixel format.
m_nPixelFormat = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, m_nPixelFormat, &pfd);
// Create the OpenGL Rendering Context.
hrc = wglCreateContext(hdc);
wglMakeCurrent(hdc, hrc);
// Basic Setup:
//
// Set color to use when clearing the background.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth(1.0f);
// Turn on backface culling
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
// Turn on depth testing
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
GLenum a = glGetError();

OnDraw(NULL);
//wglMakeCurrent(NULL, NULL);
}
void COpenGlView::oglDrawScene(void)
{
// Wireframe Mode
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_QUADS);
// Front Side
glVertex3f( 1.0f,  1.0f, 1.0f);
glVertex3f(-1.0f,  1.0f, 1.0f);
glVertex3f(-1.0f, -1.0f, 1.0f);
glVertex3f( 1.0f, -1.0f, 1.0f);
// Back Side
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f,  1.0f, -1.0f);
glVertex3f( 1.0f,  1.0f, -1.0f);
glVertex3f( 1.0f, -1.0f, -1.0f);
// Top Side
glVertex3f( 1.0f, 1.0f,  1.0f);
glVertex3f( 1.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, 1.0f,  1.0f);
// Bottom Side
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f( 1.0f, -1.0f, -1.0f);
glVertex3f( 1.0f, -1.0f,  1.0f);
glVertex3f(-1.0f, -1.0f,  1.0f);
// Right Side
glVertex3f( 1.0f,  1.0f,  1.0f);
glVertex3f( 1.0f, -1.0f,  1.0f);
glVertex3f( 1.0f, -1.0f, -1.0f);
glVertex3f( 1.0f,  1.0f, -1.0f);
// Left Side
glVertex3f(-1.0f, -1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f,  1.0f);
glVertex3f(-1.0f,  1.0f,  1.0f);
glVertex3f(-1.0f,  1.0f, -1.0f);
glEnd();
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -m_fZoom);
glTranslatef(m_fPosX, m_fPosY, 0.0f);
glRotatef(m_fRotX, 1.0f, 0.0f, 0.0f);
glRotatef(m_fRotY, 0.0f, 1.0f, 0.0f);
GLenum a = glGetError();
}

//--------------------------------------------------------
// Get an random integer within a specified range
//--------------------------------------------------------
int COpenGlView::randInt(const int& min, const int& max) {
return ((rand()%(int)(((max) + 1)-(min)))+ (min)); 
}
//--------------------------------------------------------
// Get a random float within a specified range
//--------------------------------------------------------
float COpenGlView::randFloat(const float& min, const float& max) {
float range = max - min;
float num = range * rand() / RAND_MAX;
return (num + min);
}

然后我从同一个类扩展了另外两个视图类

C3dRightView : public COpenGlView 

C3dRightView : public COpenGlView 

然后在childframe类中,我添加了splitter代码,并在splitter窗口中调用了这两个类。问题是两个opengl视图代码都可以正常工作,但如果我停止其中一个opengl的初始化,那么另一个就会显示出来。我尝试了所有的东西,但我无法在这两个不同的视图中显示两个不同图形的opengl动画。我已经检查了HDC内存映射,看起来这两个类都在使用它们的动态HDC对象的parent,但如果我停止一个代码,那么其他视图就会正常显示。

详细等级低于

class C3dRightView : public COpenGlView
{
DECLARE_DYNCREATE(C3dRightView)
protected:
GLuint m_left_texture[53];
C3dRightView();           // protected constructor used by dynamic creation
virtual ~C3dRightView();
public:
virtual void OnDraw(CDC* pDC);      // overridden to draw this view
#ifdef _DEBUG
virtual void AssertValid() const;
#ifndef _WIN32_WCE
virtual void Dump(CDumpContext& dc) const;
#endif
#endif

protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnPaint();
virtual void OnInitialUpdate();
void oglDrawScene(void);
void oglInitialize(void);
afx_msg void OnTimer(UINT_PTR nIDEvent);
};

void C3dRightView::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CView::OnPaint() for painting messages
}

void C3dRightView::OnInitialUpdate()
{
hdc = C3dRightView::GetDC()->m_hDC;
/** If i open below code then left view stop displaying model **/
COpenGlView::OnInitialUpdate();
oglInitialize();
//-=-=-=-=-=-=-==--=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
oglBeginRendering();
// TODO: Add your specialized code here and/or call the base class
}

void C3dRightView::oglInitialize(void)
{
COpenGlView::oglInitialize();
}
void C3dRightView::oglDrawScene(void)
{
// Wireframe Mode
glShadeModel(GL_SMOOTH);    
glClearColor(0.0f, 1.0f, 1.0f, 0.0f);
glLoadIdentity();
//glTranslatef(0.0f, 0.0f, -m_fZoom);//this is for zoom using left mouse click but no placing
glTranslatef(m_fPosX, m_fPosY,-m_fZoom); // this is for placing + zooming using middle scroll button mouse click
glRotatef(m_fRotX, 1.0f, 0.0f, 0.0f);//these two for mouse movement
glRotatef(m_fRotY, 0.0f, 1.0f, 0.0f);
glRotated(90,0.0f, 0.0f, -1.0f);
glRotatef(180,1.0f,0,0.0f);
GLenum a = glGetError();
glBegin(GL_TRIANGLES);                              // Start Drawing A Triangle
glColor3f(1.0f,0.0f,0.0f);                      // Red
glVertex3f( 0.0f, 1.0f, 0.0f);                  // Top Of Triangle (Front)
glColor3f(0.0f,1.0f,0.0f);                      // Green
glVertex3f(-1.0f,-1.0f, 1.0f);                  // Left Of Triangle (Front)
glColor3f(0.0f,0.0f,1.0f);                      // Blue
glVertex3f( 1.0f,-1.0f, 1.0f);                  // Right Of Triangle (Front)
glColor3f(1.0f,0.0f,0.0f);                      // Red
glVertex3f( 0.0f, 1.0f, 0.0f);                  // Top Of Triangle (Right)
glColor3f(0.0f,0.0f,1.0f);                      // Blue
glVertex3f( 1.0f,-1.0f, 1.0f);                  // Left Of Triangle (Right)
glColor3f(0.0f,1.0f,0.0f);                      // Green
glVertex3f( 1.0f,-1.0f, -1.0f);                 // Right Of Triangle (Right)
glColor3f(1.0f,0.0f,0.0f);                      // Red
glVertex3f( 0.0f, 1.0f, 0.0f);                  // Top Of Triangle (Back)
glColor3f(0.0f,1.0f,0.0f);                      // Green
glVertex3f( 1.0f,-1.0f, -1.0f);                 // Left Of Triangle (Back)
glColor3f(0.0f,0.0f,1.0f);                      // Blue
glVertex3f(-1.0f,-1.0f, -1.0f);                 // Right Of Triangle (Back)
glColor3f(1.0f,0.0f,0.0f);                      // Red
glVertex3f( 0.0f, 1.0f, 0.0f);                  // Top Of Triangle (Left)
glColor3f(0.0f,0.0f,1.0f);                      // Blue
glVertex3f(-1.0f,-1.0f,-1.0f);                  // Left Of Triangle (Left)
glColor3f(0.0f,1.0f,0.0f);                      // Green
glVertex3f(-1.0f,-1.0f, 1.0f);                  // Right Of Triangle (Left)
glEnd();    
}

第二个视图文件类似于这个

class C3dLeftView : public COpenGlView
{
DECLARE_DYNCREATE(C3dLeftView)
protected:
GLuint m_left_texture[53];
C3dLeftView();           // protected constructor used by dynamic creation
virtual ~C3dLeftView();
public:
virtual void OnDraw(CDC* pDC);      // overridden to draw this view
#ifdef _DEBUG
virtual void AssertValid() const;
#ifndef _WIN32_WCE
virtual void Dump(CDumpContext& dc) const;
#endif
#endif
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnPaint();
virtual void OnInitialUpdate();
void oglDrawScene(void);
void oglInitialize(void);
afx_msg void OnTimer(UINT_PTR nIDEvent);
};

void C3dLeftView::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CView::OnPaint() for painting messages
}
void C3dLeftView::OnInitialUpdate()
{
hdc = C3dLeftView::GetDC()->m_hDC;
COpenGlView::OnInitialUpdate();
oglInitialize();
oglBeginRendering();
// TODO: Add your specialized code here and/or call the base class
}

void C3dLeftView::oglInitialize(void)
{
COpenGlView::oglInitialize();

}
void C3dLeftView::oglDrawScene(void)
{
glShadeModel(GL_SMOOTH);    
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glLoadIdentity();
//glTranslatef(0.0f, 0.0f, -m_fZoom);//this is for zoom using left mouse click but no placing
glTranslatef(m_fPosX, m_fPosY,-m_fZoom); // this is for placing + zooming using middle scroll button mouse click
glRotatef(m_fRotX, 1.0f, 0.0f, 0.0f);//these two for mouse movement
glRotatef(m_fRotY, 0.0f, 1.0f, 0.0f);
glRotated(90,0.0f, 0.0f, -1.0f);
glRotatef(180,1.0f,0,0.0f);
GLenum a = glGetError();
glBegin(GL_TRIANGLES);                              // Start Drawing A Triangle
glColor3f(1.0f,0.0f,0.0f);                      // Red
glVertex3f( 0.0f, 1.0f, 0.0f);                  // Top Of Triangle (Front)
glColor3f(0.0f,1.0f,0.0f);                      // Green
glVertex3f(-1.0f,-1.0f, 1.0f);                  // Left Of Triangle (Front)
glColor3f(0.0f,0.0f,1.0f);                      // Blue
glVertex3f( 1.0f,-1.0f, 1.0f);                  // Right Of Triangle (Front)
glColor3f(1.0f,0.0f,0.0f);                      // Red
glVertex3f( 0.0f, 1.0f, 0.0f);                  // Top Of Triangle (Right)
glColor3f(0.0f,0.0f,1.0f);                      // Blue
glVertex3f( 1.0f,-1.0f, 1.0f);                  // Left Of Triangle (Right)
glColor3f(0.0f,1.0f,0.0f);                      // Green
glVertex3f( 1.0f,-1.0f, -1.0f);                 // Right Of Triangle (Right)
glColor3f(1.0f,0.0f,0.0f);                      // Red
glVertex3f( 0.0f, 1.0f, 0.0f);                  // Top Of Triangle (Back)
glColor3f(0.0f,1.0f,0.0f);                      // Green
glVertex3f( 1.0f,-1.0f, -1.0f);                 // Left Of Triangle (Back)
glColor3f(0.0f,0.0f,1.0f);                      // Blue
glVertex3f(-1.0f,-1.0f, -1.0f);                 // Right Of Triangle (Back)
glColor3f(1.0f,0.0f,0.0f);                      // Red
glVertex3f( 0.0f, 1.0f, 0.0f);                  // Top Of Triangle (Left)
glColor3f(0.0f,0.0f,1.0f);                      // Blue
glVertex3f(-1.0f,-1.0f,-1.0f);                  // Left Of Triangle (Left)
glColor3f(0.0f,1.0f,0.0f);                      // Green
glVertex3f(-1.0f,-1.0f, 1.0f);                  // Right Of Triangle (Left)
glEnd();    
/*************************************************************************************/

}

若视图initializupdate函数中代码下面有注释,那个么其他视图代码也可以正常工作。

COpenGlView::OnInitialUpdate();
oglInitialize();

父代码的initializupdate代码是如何为其一个子代码而不是其中两个子代码工作的。

编辑:不,原因不可能像我最初想的那样是wglMakeCurrent(),你似乎已经足够了。

然而,原因可能是您给oglInitialize()打了太多次电话。这取决于你如何创建你的视图和拆分器,但你没有发布代码。一种解决方法是限制视图实际"初始更新"的次数。

在构造函数中将hdc成员初始化为0(实际上总是初始化构造函数中的所有成员):

COpenGlView::COpenGlView()
{
hdc = 0;
// ... etc your stuff
}

hdc为0:时,只进行一次ogl初始化

void C3dRightView::OnInitialUpdate()
{
if ( hdc == 0 )
{
hdc = GetDC()->m_hDC;
COpenGlView::OnInitialUpdate();
oglBeginRendering();
}
}

这里也是:

void C3dLeftView::OnInitialUpdate()
{
if ( hdc == 0 )
{
hdc = GetDC()->m_hDC;
COpenGlView::OnInitialUpdate();
oglBeginRendering();
}
}

我相信这应该行得通。

第2版:已尝试您的代码。C3dRightView::OnInitialUpdate与我在上面发布的不同。我不太确定是什么把初始化搞砸了。例如,以下对CChildFrame::OnCreateClient的修复似乎有效:

if (!m_wndSplitter.CreateView( 0, 1, RUNTIME_CLASS(C3dRightView), CSize(cr.Width()/2, cr.Height()), pContext))
{
MessageBox(L"Error setting up splitter frames!", L"Init Error!", MB_OK | MB_ICONERROR);
return FALSE;
}
// had to add this line here:
m_wndSplitter.GetPane( 0, 1 )->SendMessage(WM_INITIALUPDATE);
return TRUE;

尽管可能会很晚,但以下是我的答案,可以在未来帮助您:)

在Ontimer函数中调用CCD_ 7函数。pdoc是指向文档类的指针。它将请求更新所有视图,并且您将使两个窗口都工作:)。