0

我正在使用 VC++ MFC 制作一个应用程序,其中我有两个不同的 opengl 窗口。我已按照此处输入链接描述的教程进行操作

我能够成功使用一个图片控件,其中 opengl 窗口显示正确的渲染,但如果我创建该控件的两个不同对象,则一个窗口不显示任何内容。

在这里解释更多是代码

m_WinGL 和 m_WinGL2 是 initDialog 内部自定义类的两个不同对象。

// Get size and position of the template textfield we created before in the dialog editor
CRect rect;
GetDlgItem(IDC_STATIC_GL)->GetWindowRect(rect);
ScreenToClient(rect);// Convert screen coordinates to client coordinates

m_WinGL.oglCreate(rect, this);// Create OpenGL Control window
m_WinGL.m_unpTimer = m_WinGL.SetTimer(1, 1, 0);// Setup the OpenGL Window's timer to render


GetDlgItem(IDC_STATIC_GL2)->GetWindowRect(rect);
ScreenToClient(rect);// Convert screen coordinates to client coordinates

m_WinGL2.oglCreate(rect, this,L"X");// Create OpenGL Control window
m_WinGL2.m_unpTimer = m_WinGL2.SetTimer(1, 1, 0);// Setup the OpenGL Window's timer to render

这是自定义控件的类

头文件

#pragma once
#include "afxwin.h"

#include <gl/gl.h>
#include <gl/glu.h>

class COpenGLControl : public CWnd
{
    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;

    private:
        /*******************/
        /* Private Members */
        /*******************/
        // Window information
        CWnd  *hWnd;
        HDC   hdc;          
        HGLRC hrc;          
        int   m_nPixelFormat;
        CRect m_rect;
        CRect m_oldWindow;
        CRect m_originalRect;

    public:
        COpenGLControl(void);
        virtual ~COpenGLControl(void);

        void oglCreate(CRect rect, CWnd *parent,CString strWindowName=L"OpenGl");
        void oglInitialize(void);
        void oglDrawScene(void);

        // Added message classes:
        afx_msg void OnPaint();
        afx_msg void OnSize(UINT nType, int cx, int cy);
        afx_msg void OnDraw(CDC *pDC);
        afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
        afx_msg void OnTimer(UINT nIDEvent);
        afx_msg void OnMouseMove(UINT nFlags, CPoint point);

        DECLARE_MESSAGE_MAP()
};

.cpp 文件

    #include "stdafx.h"
    #include "OpenGLControl.h"

    COpenGLControl::COpenGLControl(void)
    {
        m_fPosX = 0.0f;     // X position of model in camera view
        m_fPosY = 0.0f;     // Y position of model in camera view
        m_fZoom = 10.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_bIsMaximized = false;
    }

    COpenGLControl::~COpenGLControl(void)
    {
    }

    BEGIN_MESSAGE_MAP(COpenGLControl, CWnd)
        ON_WM_PAINT()
        ON_WM_SIZE()
        ON_WM_CREATE()
        ON_WM_TIMER()
        ON_WM_MOUSEMOVE()
    END_MESSAGE_MAP()

    void COpenGLControl::OnPaint()
    {
        //CPaintDC dc(this); // device context for painting
        ValidateRect(NULL);
    }

    void COpenGLControl::OnSize(UINT nType, int cx, int cy)
    {
        CWnd::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;
            }
        }
    }

    int COpenGLControl::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
        if (CWnd::OnCreate(lpCreateStruct) == -1) return -1;

        oglInitialize();

        return 0;
    }

    void COpenGLControl::OnDraw(CDC *pDC)
    {
        // If the current view is perspective...
        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);
    }

    void COpenGLControl::OnTimer(UINT nIDEvent)
    {
        switch (nIDEvent)
        {
            case 1:
            {
                // Clear color and depth buffer bits
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

                // Draw OpenGL scene
                oglDrawScene();

                // Swap buffers
                SwapBuffers(hdc);

                break;
            }

            default:
                break;
        }

        CWnd::OnTimer(nIDEvent);
    }

    void COpenGLControl::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)0.5f * 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)0.1f * diffY;
        }

        // Middle mouse button
        else if (nFlags & MK_MBUTTON)
        {
            m_fPosX += (float)0.05f * diffX;
            m_fPosY -= (float)0.05f * diffY;
        }

        OnDraw(NULL);

        CWnd::OnMouseMove(nFlags, point);
    }

    void COpenGLControl::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;
    }

    void COpenGLControl::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);

        // Send draw request
        OnDraw(NULL);
    }

    void COpenGLControl::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();
    }
4

1 回答 1

4

OpenGL 是一个线程全局上下文状态机。这意味着,您必须将当前线程的 OpenGL 上下文切换到正确的窗口,以便绘图命令最终到达您想要的位置。

在您进行 OpenGL 调用的每个成员函数中,放在开头

wglMakeCurrent(hdc, hrc);

在你离开函数之前(即在最后,或者在返回之前)

wglMakeCurrent(NULL, NULL);

顺便说一句:您可以为任意数量的窗口使用单个 OpenGL 上下文,只要它们共享相同的视觉属性,即,如果您SetPixelFormatDescriptor为每个希望上下文使用的窗口使用相同的 PFD 调用。

最后但并非最不重要的一点是,所有在中找到的代码OnSize和所有“基本设置”onInitialize都应放入绘图代码中。你OnDraw的也不是很有用。

于 2012-09-01T12:36:24.647 回答