65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Windows 窗体上创建 OpenGL 视图

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (41投票s)

2006 年 10 月 20 日

3分钟阅读

viewsIcon

686688

downloadIcon

20981

如何在 Windows 窗体上创建 OpenGL 视图。

Screenshot Image

引言

本文介绍了一种非常简洁明了的方法,使用托管 C++ 在 Windows 窗体上渲染 OpenGL 窗口。此方法不需要任何插件、第三方 DLL 或 ActiveX 组件,而这些组件通常通过 C# Windows 窗体演示。此实现是纯 .NET,使用托管 C++。本文假定读者具有 OpenGL 的工作知识,并且正在使用 Microsoft Visual Studio .NET 8.0。

背景

在 MFC 视图上呈现 OpenGL 窗口非常简单易于实现。然而,Windows 窗体的出现带来了一些问题。窗口设备上下文的概念在 Windows 窗体中并不真正存在。已经有一些在 Windows 窗体上实现 OpenGL 的方法,但这些方法依赖于包含 MFC 或 Win32 SDK 调用的 DLL 或 ActiveX 组件。这些实现也假设程序员正在使用 C#。虽然使用 C# 有一些优势,但我怀疑,像我自己一样,我不想为了利用 Windows 窗体而用 C# 重写我现有的应用程序。我也怀疑许多 C++ 程序员不希望或不能因为公司原因或其他原因而迁移到 C#。这里的实现使用纯托管 C++ 和 .NET。

实现

首先,我们需要一个新的 Windows 窗体应用程序来工作。创建一个新的 Windows 窗体应用程序(文件 -> 新建 -> 项目 -> Visual C++ -> CLR -> Windows 窗体应用程序)。

现在,我们将构建一个可以在多个 Windows 窗体上使用的 OpenGL 类。这可以很容易地转换为可以添加到设计时设计器的控件,但我不会介绍这一点。

为该类创建一个新的头文件,我将其命名为OpenGL.h,并将以下代码段复制到其中。我将在代码片段下方注释代码的实际作用: -

#pragma once

#include <windows.h>
#include <GL/gl.h>    

using namespace System::Windows::Forms;

namespace OpenGLForm
{
    public ref class COpenGL: 
      public System::Windows::Forms::NativeWindow

我们在这里所做的只是包含 OpenGL 所需的头文件,并为 OpenGL 声明一个托管 C++ 类。

{
public:
    COpenGL(System::Windows::Forms::Form ^ parentForm, 
            GLsizei iWidth, GLsizei iHeight)
    {
        CreateParams^ cp = gcnew CreateParams;

        // Set the position on the form
        cp->X = 100;
        cp->Y = 100;
        cp->Height = iWidth;
        cp->Width = iHeight;

        // Specify the form as the parent.
        cp->Parent = parentForm->Handle;

        // Create as a child of the specified parent
        // and make OpenGL compliant (no clipping)
        cp->Style = WS_CHILD | WS_VISIBLE | 
                    WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

        // Create the actual window
        this->CreateHandle(cp);

        m_hDC = GetDC((HWND)this->Handle.ToPointer());

        if(m_hDC)
            MySetPixelFormat(m_hDC);
    }

此构造函数接受父窗体、OpenGL 区域的宽度和 OpenGL 区域的高度作为参数。

System::Windows::Forms::CreateParams 结构允许我们创建一个 Win32 窗口。我们指定 WS_CLIPSIBLINGS | WS_CLIPCHILDREN 以便我们的 OpenGL 显示不会被剪裁。

virtual System::Void Render(System::Void)
{
    // Clear the color and depth buffers.
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f) ;
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

这是一个重写的函数,它只是用黑色填充 OpenGL 区域。

System::Void SwapOpenGLBuffers(System::Void)
{
    SwapBuffers(m_hDC) ;
}

在 OpenGL 渲染之后直接调用此函数,以将 OpenGL 缓冲区的内容放入我们的窗口中。

private:
    HDC m_hDC;
    HGLRC m_hglrc;

这些是我们与窗体交互所需的指针。

protected:
    ~COpenGL(System::Void)
    {
        this->DestroyHandle();
    }

销毁窗体时,我们处理我们的窗口。

    GLint MySetPixelFormat(HDC hdc)
    {
        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 
            32,                               // 32-bit z-buffer     
            0,                                // no stencil buffer 
            0,                                // no auxiliary buffer 
            PFD_MAIN_PLANE,                   // main layer 
            0,                                // reserved 
            0, 0, 0                           // layer masks ignored 
        }; 
    
        GLint  iPixelFormat; 
     
        // get the device context's best, available pixel format match 
        if((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0)
        {
            MessageBox::Show("ChoosePixelFormat Failed");
            return 0;
        }
         
        // make that match the device context's current pixel format 
        if(SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE)
        {
            MessageBox::Show("SetPixelFormat Failed");
            return 0;
        }
    
        if((m_hglrc = wglCreateContext(m_hDC)) == NULL)
        {
            MessageBox::Show("wglCreateContext Failed");
            return 0;
        }
        
        if((wglMakeCurrent(m_hDC, m_hglrc)) == NULL)
        {
            MessageBox::Show("wglMakeCurrent Failed");
            return 0;
        }
    
        return 1;
    }
};

用于为 Win32 SDK / MFC 设备上下文设置像素格式的标准函数。有关此内容的更多信息,请参见 OpenGL 网站。

如果您复制了所有代码段,它应该可以正常构建,请不要忘记将openGL32.libgdi32.libUser32.lib添加到您的项目(项目 -> 属性 -> 配置 -> 所有配置 -> 链接器 -> 输入)。

测试容器

打开您的窗体的代码视图,并将头文件添加到您的 OpenGL 类,并在您的窗体中添加一个指向该类的成员变量。接下来,更改您的窗体的构造函数: -

OpenGL = gcnew COpenGL(this, 640, 480);

如果您现在重写您的Paint()函数(窗体设计器 -> 属性 -> 事件 -> 外观 -> Paint)并从此函数调用您的 OpenGL 渲染器

private: System::Void timer1_Tick(System::Object^  sender, 
                                  System::EventArgs^  e)
{
    UNREFERENCED_PARAMETER(sender);
    UNREFERENCED_PARAMETER(e);
    OpenGL->Render();
    OpenGL->SwapOpenGLBuffers();
}

运行您的应用程序!就是这样,简单!在 Windows 窗体上使用 OpenGL!

关注点

此方法有效,因为 System::Windows::Forms::NativeWindow 提供了窗口句柄和窗口过程的低级封装。这允许我们将该类视为 HWND(请参阅我的用户控件)。

我稍微更改了演示,以显示它更可能被使用。我这样做是因为我特意保持 OpenGL 的简单性(我甚至没有设置视口或视锥,但这是完全特定于应用程序的,我的文章旨在展示在 Windows 窗体上创建 OpenGL 视图的方法)。

历史

  • 2006/10/18 - 将文章提交到 CodeProject。
© . All rights reserved.