Click here to Skip to main content
15,867,835 members
Articles / Desktop Programming / ATL
Article

How to add OpenGL support to ATL controls

Rate me:
Please Sign up or sign in to vote.
4.57/5 (7 votes)
28 Sep 2002CPOL2 min read 111.4K   1.4K   44   16
An article describing the step-by-step process of adding basic OpenGL support to an ATL control

Introduction

This tutorial will demonstrate how to add OpenGL support to an ATL control, and constitutes a cut-down, organized version of the ATL OpenGL demo that comes with Visual C++ in a more printable and easier-to-digest format. In order to work with this tutorial, you must create an ATL control in your project. What follows below is a step-by-step guide to adding the most basic OpenGL support to an ATL control.

Note: though I prefix function declarations with CMyControl::, I would recommend writing these functions inline (in the header file) and if you do that, the prefix must be removed.

  1. Add support for headers <gl/gl.h> and <gl/glu.h>; Add support for opengl32.lib and glu32.lib libraries.

    This can be done by adding the following four lines at the end of your stdafx.h file:

    C++
    #include <gl/gl.h>
    #include <gl/glu.h>
    #pragma comment(lib, "opengl32.lib")
    #pragma comment(lib, "glu32.lib")
  2. Add an OpenGL rendering context variable to your control class:
    C++
    // OpenGL rendering context
    HGLRC m_hRC;
    Now make a function to choose the OpenGL pixel format. This function will take a device context handle as a parameter and would set pixel format specifically for this device context. The function should look like the following:
    C++
    // Set OpenGL pixel format for given DC
    BOOL MyControl::SetupPixelFormat(HDC hdc)
    {
        static 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
        };
        int pixelformat;
    
        if ((pixelformat = ChoosePixelFormat(hdc, &pfd)) == 0)
        {
            ATLASSERT(FALSE);
            return FALSE;
        }
    
        if (SetPixelFormat(hdc, pixelformat, &pfd) == FALSE)
        {
            ATLASSERT(FALSE);
            return FALSE;
        }
    
        return TRUE;
    }
  3. Make a function that would create an OpenGL rendering context and initialize the viewport. Note that after setting the current rendering context, we can begin calling OpenGL functions such as glViewport.
    C++
    // Create rendering context given device context and control bounds
    void MyControl::CreateContext(HDC hdc, RECT& rc)
    {
        PIXELFORMATDESCRIPTOR pfd;
        if (!SetupPixelFormat(hdc))
            return;
    
        int n = GetPixelFormat(hdc);
        DescribePixelFormat(hdc, n, sizeof(pfd), &pfd);
        m_hRC = wglCreateContext(hdc);
        wglMakeCurrent(hdc, m_hRC);
    
        // OpenGL code starts here - below is an example
        int width = rc.right - rc.left;
        int height = rc.bottom - rc.top;
    
        glViewport(0, 0, width, height);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(-width/2, width/2, -height/2, height/2);
        glMatrixMode(GL_MODELVIEW);
    }
  4. Add a call to the above function from OnCreate. To do that, you first have to create a WM_CREATE handler. Use the Messages button on the Properties toolbar to add a handler. Then, find the function and add code similar to the following:
    C++
    LRESULT CMyControl::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/,
        LPARAM /*lParam*/, BOOL& /*bHandled*/)
    {
        HDC hdc = GetDC();
        RECT rc;
        GetClientRect(&rc);
        CreateContext(hdc, rc);
    
        return 0;
    }
  5. In a similar fashion, add code for OnDestroy (WM_DESTROY) to clear the rendering context and delete it.
    LRESULT CMyControl::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
    {
      wglMakeCurrent(NULL, NULL);
    
      if (m_hRC)
      {
        wglDeleteContext(m_hRC);
        m_hRC = NULL;
      }
    
      return 0;
    }
  6. Handling WM_SIZE is also important. Whenever the window resizes, we must nullify the current OpenGL rendering context and recreate it from scratch.
    C++
    LRESULT CMyControl::OnSize(UINT /*uMsg*/, WPARAM /*wParam*/,
        LPARAM /*lParam*/, BOOL& /*bHandled*/)
    {
        // when resized, recreate the device context
        wglMakeCurrent(NULL,    NULL);
        if (m_hRC)
        {
            wglDeleteContext(m_hRC);
            m_hRC = NULL;
        }
        HDC hdc = GetDC();
        RECT rc;
        GetClientRect(&rc);
        CreateContext(hdc, rc);
    
        return 0;
    }

    All done. Remember! You can use glaux library (glaux32.lib, <glaux.h>) to implement functionality equivalent to the GLUT library (though you probably won't need the windowing functions). For example, you can use auxDIBImageLoad to load bitmaps to use as textures. However, I would recommend using more advanced methods of texturing, for example using PNG files for textures that have an alpha channel.

  7. Rendering can be done in OnDraw. Here is an example:
    C++
    HRESULT OnDraw(ATL_DRAWINFO& di)
    {
        HDC hdc = di.hdcDraw;
        RECT& rc = *(RECT*)di.prcBounds;
    
    
        wglMakeCurrent(hdc, m_hRC);
    
        glClearColor(1.0f, 0.0f, 0.0f, 10.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    
        glPushMatrix();
    
        // compute dimensions of a quarter of the control
        SIZE qtrSize = { 
            (rc.right - rc.left) / 2, 
            (rc.bottom - rc.top) / 2 };
    
        glBegin(GL_QUADS);
            glColor3ub(255, 0, 0);
            glVertex3s(-qtrSize.cx, -qtrSize.cy, 0);
    
            glColor3ub(0, 255, 0);
            glVertex3s(qtrSize.cx, -qtrSize.cy, 0);
    
            glColor3ub(0, 0, 255);
            glVertex3s(qtrSize.cx, qtrSize.cy, 0);
    
            glColor3ub(255, 255, 255);
            glVertex3s(-qtrSize.cx, qtrSize.cy, 0);
        glEnd();
    
        glPopMatrix();
    
        glFinish();
        SwapBuffers(wglGetCurrentDC());
    
        return S_OK;
    }

Possible Improvements

I believe it is possible to create a mixin class/abstract superclass that will add OpenGL functionality to an ATL control in a much cleaner fashion than a bunch of functions/message handlers inside every control class. Writing all this code for each ATL control (if you have many in your project) is tedious: it would be better if you could specify that your control inherits from some CControlOpenGL<YourControl> class. This functionality, as well as more advanced OpenGL modes and options may make up material for another tutorial.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder ActiveMesa
United Kingdom United Kingdom
I work primarily with the .NET technology stack, and specialize in accelerated code production via code generation (static or dynamic), aspect-oriented programming, MDA, domain-specific languages and anything else that gets products out the door faster. My languages of choice are C# and C++, though I'm open to suggestions.

Comments and Discussions

 
QuestionDoesn't render anything Pin
DrkAngr7-Jan-09 12:21
DrkAngr7-Jan-09 12:21 
QuestionNo hardware acceleration Pin
blaless27-Aug-07 5:22
blaless27-Aug-07 5:22 
Hi All,

At Eximion we create web games on our own player. For some time now we have had a problem we cannot fix. Even this article didn't help to fix it. Do you want to earn money with bug fixing? More details at our bounty bug site.

We have an ATL based ActiveX control that uses OpenGL for rendering. This control seems to crash on random computers. It seems that on computers where this crash occurs an invalid pixel format is chosen.

More information can be found here.

Greetings,
The Eximion Team
QuestionActiveX control crashes Pin
User 121107122-Sep-06 5:04
User 121107122-Sep-06 5:04 
AnswerRe: ActiveX control crashes Pin
Dmitri Nеstеruk27-Feb-07 19:15
Dmitri Nеstеruk27-Feb-07 19:15 
GeneralRe: ActiveX control crashes Pin
vyacheslav avdeyev4-Nov-07 22:11
vyacheslav avdeyev4-Nov-07 22:11 
GeneralRe: ActiveX control crashes Pin
Dmitri Nеstеruk5-Nov-07 1:20
Dmitri Nеstеruk5-Nov-07 1:20 
AnswerRe: ActiveX control crashes Pin
luisperdigao26-Jul-08 0:29
luisperdigao26-Jul-08 0:29 
Questionhow to create a activex control that can be used in vb6? such as an example of atlopengldemo Pin
ictory18-May-05 2:40
ictory18-May-05 2:40 
GeneralAdding ATL wizard setup Pin
rbtoaks4-Jun-04 6:14
rbtoaks4-Jun-04 6:14 
GeneralRe: Adding ATL wizard setup Pin
Anonymous23-Jul-04 1:08
Anonymous23-Jul-04 1:08 
GeneralRe: Adding ATL wizard setup Pin
rbtoaks23-Jul-04 6:31
rbtoaks23-Jul-04 6:31 
Questionpossible to create transparent opengl windows? Pin
BugByter23-Feb-04 11:14
BugByter23-Feb-04 11:14 
AnswerRe: possible to create transparent opengl windows? Pin
Anonymous25-May-04 1:09
Anonymous25-May-04 1:09 
Generalresize Pin
Mikko Mononen29-Sep-02 22:43
Mikko Mononen29-Sep-02 22:43 
QuestionWindowOnly ? Pin
Anonymous29-Sep-02 12:24
Anonymous29-Sep-02 12:24 
AnswerRe: WindowOnly ? Pin
Anonymous4-Feb-03 1:06
Anonymous4-Feb-03 1:06 

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

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