Я хочу создать приложение, в котором приложение View будет разделено на 3D-модели OpenGL в двух разных видах, прикрепленных к Childframe с помощью сплиттера. Для этого я сделал родительский класс расширенным из класса представления, и внутри этого класса я инициализировал весь код, необходимый для 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 я добавил код разделителя и вызвал эти два класса в окне разделителя. Проблема в том, что код представления opengl работает нормально, но если я остановлю одну из инициализаций opengl, то отобразится другая. Я попробовал все, и я не могу отобразить две разные графические анимации OpenGL в обоих этих двух разных видах. Я проверил карту памяти HDC, и кажется, что оба класса используют parent по отношению к их динамическому объекту hdc, но если я остановлю один код, тогда другие представления будут отображаться правильно.
классы детали ниже
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
#endifprotected:
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();
/*************************************************************************************/}
если комментарий ниже кода внутри функции initialupdate представления, то другие коды представления работают нормально.
COpenGlView::OnInitialUpdate();
oglInitialize();
кое-как, как начальный код обновления родительского кода работает для его одного потомка, а не двух из них.
Редактировать: никакой причины быть не может wglMakeCurrent()
Как я и думал вначале, вы, кажется, называете это достаточно.
Причиной может быть то, что вы называете oglInitialize()
слишком много раз, однако. Это зависит от того, как вы создаете свои представления и разделители, но тот код, который вы не опубликовали. Один из способов исправить это — ограничить, сколько раз ваши представления будут фактически «первоначально обновляться».
Инициализируйте ваш hdc
член до 0 в конструкторе (фактически всегда инициализировать все члены в конструкторах):
COpenGlView::COpenGlView()
{
hdc = 0;
// ... etc your stuff
}
Выполните инициализацию ogl только один раз, когда hdc
это 0:
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();
}
}
Это должно работать, я верю.
Edit2: Пробовал твой код. 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 pdoc->UpdateAll(NULL,NULL,NULL)
функция. pdoc — указатель на класс ваших документов. Он будет запрашивать все представления для обновления, и вы получите работающие оба окна :).