具有两个OpenGL图形视图的MFC MDI拆分器不起作用

时间:2012-11-13 21:15:59

标签: c++ opengl mfc views mdi

我想创建一个应用程序,其中应用程序视图将使用拆分器连接到Childframe的两个不同视图中的OpenGL 3d模型进行划分。为此,我创建了一个从视图类扩展的父类,在这个类中我初始化了所有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 

然后在子帧类中我添加了拆分器代码并在拆分器窗口中调用这两个类。问题是opengl视图代码工作正常,但如果我停止其中一个opengl初始化然后另一个显示。我尝试了一切,我不能在这两个不同的视图中显示两个不同的图形opengl动画。我已经检查了HDC内存映射,看起来两个类都使用父级动态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
#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();    

    /*************************************************************************************/


}

如果在视图的initialupdate函数内的代码下方注释,则其他视图代码可以正常工作。

    COpenGlView::OnInitialUpdate();
    oglInitialize();

一些父代码的初始更新代码如何适用于其中一个子代而不是其中两个代码。

2 个答案:

答案 0 :(得分:1)

编辑:没有理由不能像我最初想的那样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;

答案 1 :(得分:-1)

尽管可能会迟到,但这是我的答案,可以帮助你将来:)

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