Click here to Skip to main content
11,431,829 members (62,918 online)
Click here to Skip to main content

Creating an OpenGL view on a Windows Form

, 20 Oct 2006
Rate this:
Please Sign up or sign in to vote.
How to create an OpenGL view on a Windows Form.

Screenshot Image

Introduction

This article presents a very clean and simple method to render an OpenGL window on a Windows Forms using Managed C++. This method requires no add-ins, third party DLLs, or ActiveX components, often demonstrated with C# Windows Forms. This implementation is in pure .NET using Managed C++. This article assumes the reader has a working knowledge of OpenGL and is using Microsoft Visual Studio .NET 8.0.

Background

Presenting an OpenGL window on an MFC view was very straight forward and easy to implement. The advent of Windows Forms however presents some problems. The concept of the window Device Context does not really exist in Windows Forms. There are some implementations of OpenGL on Windows Forms already out there but these rely on DLLs or ActiveX components containing MFC or Win32 SDK calls. These implementations also assume that the programmer is using C#. Whilst there are some advantages of using C#, I suspect that, like myself, I don't want to rewrite my existing applications in C# just to take advantage of Windows Forms. I also suspect that many C++ programmers don't want or can't move to C#, for corporate reasons or whatever. The implementation here is using pure Managed C++ and .NET.

The implementation

Firstly, we need a new Windows Forms application to work with. Create a new a new Windows Forms application (File -> New -> Project -> Visual C++ -> CLR -> Windows Forms Application).

We will now build an OpenGL class that can be used on several Windows Forms. This can be easily converted into a control that can be added to the Design Time Designer, but I'm not covering that.

Create a new header file for the class, I called my OpenGL.h and copy the following code snippets into it. I will comment below the snippet what the code actually does: -

#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

All we've done here is include the necessary headers for OpenGL and decoare a managed C++ class for OpenGL.

{
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);
    }

This constructor takes parameters of a parent form, the width of the OpenGL area and the height of the OpenGL area.

The System::Windows::Forms::CreateParams structure allows us to create a Win32 window. We specify WS_CLIPSIBLINGS | WS_CLIPCHILDREN so that our OpenGL display won't be clipped.

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);
}

This is an overridden function that simply fills the OpenGL area with black.

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

This is called directly after the OpenGL rendering to put the contents of the OpenGL buffer into our window.

private:
    HDC m_hDC;
    HGLRC m_hglrc;

These are the pointers we need to interact with the Form.

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

When destroying the Form, we dispose of our window.

    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;
    }
};

Standard function to set a pixel format for a Win32 SDK / MFC Device Context. See OpenGL websites for more on this.

If you copy all of the snippets it should build fine, don't forget to add openGL32.lib, gdi32.lib, and User32.lib to your project (Project -> Properties -> Configuration -> All Configurations -> Linker -> Input).

The test container

Open the code view to your form and add the header to your OpenGL class and add a member variable that is a pointer to the class in your Form. Next, change your Form's constructor: -

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

If you now override your Paint() function (Forms Designer -> Properties -> Events -> Appearance -> Paint) and call your OpenGL renderer from this:

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

Run your application! That's it, simply! OpenGL on a Windows Forms!

Points of interest

This method works because the System::Windows::Forms::NativeWindow provides a low-level encapsulation of a window handle and a window procedure. This allows us to treat the class as a HWND (see my user control).

I've changed the demo slightly to show it is more likely to be used. I did this because I've purposefully kept the OpenGL simple (I've not even setup the viewport or viewing frustrum but that is entirely application specific, my article is to show the method of creating an OpenGL view on a Windows Forms).

History

  • 2006/10/18 - Submitted article to CodeProject.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Benjamin Wootton

United States United States
No Biography provided

Comments and Discussions

 
GeneralForm's constructor --------> doesn't work Pin
M.Siyamalan10-Mar-10 19:20
memberM.Siyamalan10-Mar-10 19:20 
AnswerRe: Form's constructor --------> doesn't work Pin
burkeerr4-Oct-10 6:13
memberburkeerr4-Oct-10 6:13 
GeneralResizing the control Pin
rwdougla2-Nov-09 15:56
memberrwdougla2-Nov-09 15:56 
GeneralRe: Resizing the control Pin
z0ika2-Nov-09 22:46
memberz0ika2-Nov-09 22:46 
AnswerRe: Resizing the control Pin
Anika Uhlemann17-Feb-10 5:03
memberAnika Uhlemann17-Feb-10 5:03 
GeneralRe: Resizing the control Pin
M.Siyamalan8-Mar-10 23:59
memberM.Siyamalan8-Mar-10 23:59 
GeneralRe: Resizing the control Pin
M.Siyamalan9-Mar-10 0:07
memberM.Siyamalan9-Mar-10 0:07 
GeneralRe: Resizing the control Pin
fly-sci23-Apr-11 6:58
memberfly-sci23-Apr-11 6:58 
GeneralError on this code Pin
Member 389080112-Oct-09 7:13
memberMember 389080112-Oct-09 7:13 
GeneralRe: Error on this code Pin
rwdougla30-Oct-09 12:07
memberrwdougla30-Oct-09 12:07 
GeneralRe: Error on this code Pin
rwdougla30-Oct-09 12:15
memberrwdougla30-Oct-09 12:15 
GeneralRe: Error on this code Pin
z0ika2-Nov-09 4:51
memberz0ika2-Nov-09 4:51 
GeneralRe: Error on this code Pin
rwdougla2-Nov-09 15:54
memberrwdougla2-Nov-09 15:54 
GeneralRe: Error on this code Pin
z0ika2-Nov-09 22:49
memberz0ika2-Nov-09 22:49 
Did you try calling the Resize function before MyPxelFormat function? The opengl-view appears to me, when i call glViewPort before the pixel-format stuff. I'm talking about the functions from the downloadable content, not of the code pasted in this tut.
GeneralRe: Error on this code Pin
rwdougla4-Nov-09 4:52
memberrwdougla4-Nov-09 4:52 
GeneralRe: Error on this code Pin
z0ika2-Nov-09 4:51
memberz0ika2-Nov-09 4:51 
GeneralRe: Error on this code Pin
z0ika2-Nov-09 4:49
memberz0ika2-Nov-09 4:49 
GeneralRe: Error on this code Pin
rtrahan317-Jan-10 12:49
memberrtrahan317-Jan-10 12:49 
GeneralRe: Error on this code Pin
kachii2-Mar-10 8:56
memberkachii2-Mar-10 8:56 
GeneralRe: Error on this code Pin
Jace Priester17-Jun-10 14:25
memberJace Priester17-Jun-10 14:25 
Generalsyntax error : 'public' Pin
micahhoover15-Jan-09 11:18
membermicahhoover15-Jan-09 11:18 
GeneralCapturing mouse moves Pin
hain4-Dec-08 8:18
memberhain4-Dec-08 8:18 
GeneralRe: Capturing mouse moves Pin
mediaabc24-Feb-10 23:35
membermediaabc24-Feb-10 23:35 
GeneralC# and OpenSG?! Pin
njss27-Nov-08 23:07
membernjss27-Nov-08 23:07 
GeneralFYI: source code not the same for both downloads Pin
m00sej00se26-Oct-08 9:36
memberm00sej00se26-Oct-08 9:36 
GeneralRe: FYI: source code not the same for both downloads Pin
ant-damage28-Aug-09 3:05
memberant-damage28-Aug-09 3:05 
QuestionHelp "System.NullReferenceException" [modified] Pin
jpnatural15-Sep-08 14:17
memberjpnatural15-Sep-08 14:17 
AnswerRe: Help "System.NullReferenceException" Pin
jpnatural23-Sep-08 14:21
memberjpnatural23-Sep-08 14:21 
GeneralRe: Help "System.NullReferenceException" Pin
ant-damage28-Aug-09 7:26
memberant-damage28-Aug-09 7:26 
GeneralPlease help! System.Access.Violation exception Pin
jbower10-Aug-08 16:08
memberjbower10-Aug-08 16:08 
GeneralC2061 on CreateParams Pin
Athos19843-Jul-08 22:21
memberAthos19843-Jul-08 22:21 
GeneralUpdating Graphics in Real Time Pin
Member 414387722-Jun-08 21:46
memberMember 414387722-Jun-08 21:46 
GeneralOpenGL Panel Pin
hain16-May-08 4:14
memberhain16-May-08 4:14 
GeneralRe: OpenGL Panel Pin
hain4-Dec-08 7:57
memberhain4-Dec-08 7:57 
Generalmouse position over OpenGL client Pin
Scott Wojtowicz4-Mar-08 20:23
memberScott Wojtowicz4-Mar-08 20:23 
Questionmdi - can you make this form an mdi parent or an mdi child? Pin
Jackson R. Jones31-Jan-08 17:18
memberJackson R. Jones31-Jan-08 17:18 
AnswerRe: mdi - can you make this form an mdi parent or an mdi child? Pin
m00sej00se26-Oct-08 8:36
memberm00sej00se26-Oct-08 8:36 
GeneralJust getting a white rectangle in my window Pin
Bevan C Bird26-Jan-08 20:25
memberBevan C Bird26-Jan-08 20:25 
GeneralResizing multiple panels (2 for instance) Pin
sangoyann9-Dec-07 8:26
membersangoyann9-Dec-07 8:26 
GeneralRe: Resizing multiple panels (2 for instance) Pin
matze198423-Jan-08 5:46
membermatze198423-Jan-08 5:46 
GeneralRe: Resizing multiple panels (2 for instance) Pin
matze198423-Jan-08 6:47
membermatze198423-Jan-08 6:47 
GeneralAdding Button Controls Pin
toddy19856-Nov-07 9:14
membertoddy19856-Nov-07 9:14 
GeneralRe: Adding Button Controls Pin
matze198423-Jan-08 5:52
membermatze198423-Jan-08 5:52 
QuestionRe: Adding Button Controls Pin
toddy198522-Feb-08 8:35
membertoddy198522-Feb-08 8:35 
GeneralRun Time Error: Object reference not set to an instance of an object. Pin
jpummill5-Nov-07 9:36
memberjpummill5-Nov-07 9:36 
GeneralRe: Run Time Error: Object reference not set to an instance of an object. Pin
jpummill5-Nov-07 10:02
memberjpummill5-Nov-07 10:02 
QuestionDisplay Lists Pin
revillusion4402-Oct-07 2:24
memberrevillusion4402-Oct-07 2:24 
GeneralRe: Display Lists Pin
BugX14-Mar-08 13:09
memberBugX14-Mar-08 13:09 
QuestionWhy this example doesn't work with me? Pin
WMendes17-Sep-07 4:19
memberWMendes17-Sep-07 4:19 
QuestionTransparent Panel + Native Window + Mouse Event? Pin
spm_manage12-Jun-07 4:37
memberspm_manage12-Jun-07 4:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150428.2 | Last Updated 20 Oct 2006
Article Copyright 2006 by Benjamin Wootton
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid