C++ C++ C# C# ASP.NET Security ASP.NET Security ASM ASM Скачать Скачать Поиск Поиск Хостинг Хостинг  
  Программа для работы с LPT портом...
Язык: .NET — ©Alexey...
  "ASP.NET Atlas" – AJAX в исполнении Micro...
Язык: .NET — ©legigor@mail.ru...
  "Невытесняющая" Многопоточность...
Язык: C/C++ — ©...
  Update World C++: Сборник GPL QT исходников
  Весь сайт целиком можно загрузить по ссылкам из раздела Скачать
Letyshops [lifetime]

 Integrating C# and OpenGL / Graphics / C#

Sample screenshot

Introduction

For a long time I wondered how to integrate OpenGL and C#. There isn't any "official" approach to the problem to date. The .NET framework design does not provide any interface to the OpenGL API yet. Personally I find C# very straightforward and easier to debug compared to C++, so I decided to face the problem by myself.

The idea

The idea was to develop one OpenGL application mixing the code of the two following articles:

Basically, the former explains how to modify a MFC windows control to make it run in a C# windows Form while the latter how to modify a MFC CView class to show OpenGL graphics. I highly recommend to read these articles before trying to understand the code provided.

Implementation

Mixing the code was quite simple. First of all I added to the MFC Control the basic OpenGL functionalities:

BEGIN_MESSAGE_MAP(COpenGLCtrl, CWnd)
    //{{AFX_MSG_MAP(COpenglWnd)
    ON_WM_SIZE()
    ON_WM_ERASEBKGND()
    ON_WM_PAINT()
    ON_WM_DESTROY()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

//
// OnSize
//
void COpenglWnd::OnSize(UINT nType, int cx, int cy) 
{
    
    TRACE0("OnSize\r\n");

    CWnd::OnSize(nType, cx, cy);

    if ((cx <= 0) || (cy <= 0)) return;

    CClientDC dc(this);

    //
    // Make the rendering context m_hrc current
    //
    BOOL bResult = wglMakeCurrent(dc.m_hDC, m_hrc);
    
    if (!bResult) {

        TRACE("wglMakeCurrent Failed %x\r\n", GetLastError() ) ;

        return;

    }

    //
    // Set up the mapping of 3-space to screen space
    //
    GLdouble gldAspect = (GLdouble) cx / (GLdouble) cy;
    glMatrixMode(GL_PROJECTION);	OutputGlError("MatrixMode") ;
    glLoadIdentity();
    gluPerspective(30.0, gldAspect, 1.0, 10.0);
    glViewport(0, 0, cx, cy);

    //
    // No rendering context will be current.
    //
    wglMakeCurrent(NULL, NULL);    

    if (GetSafeHwnd())
        Invalidate();
}

//
//    OnEraseBkgnd
//
BOOL COpenglWnd::OnEraseBkgnd(CDC* pDC) 
{

//    return CWnd::OnEraseBkgnd(pDC);

    return TRUE;
}

//
// OnPaint
//
void COpenglWnd::OnPaint()
{

    CPaintDC dc(this); // Device context for painting

    // Make the HGLRC current
    BOOL bResult = wglMakeCurrent(dc.m_hDC, m_hrc);

    if (!bResult)
    
        TRACE("wglMakeCurrent Failed %x\r\n", GetLastError());
    
    // Draw    
    DrawScene(); 

    //Swap Buffers
    SwapBuffers(dc.m_hDC);

    wglMakeCurrent(NULL, NULL);

}

//
// OnDestroy
//
void COpenglWnd::OnDestroy() 
{

    CWnd::OnDestroy();
    wglMakeCurrent(NULL, NULL); 

    if (m_hrc) {
        wglDeleteContext(m_hrc);
        m_hrc = NULL;
    }    
    
}		

As you can see on Dale's article we need to overload the OnCreate method for OpenGL initialization. The problem is that the MFC Control will never receive the WM_CREATE message because - obviusly - the subclassing operation takes place after the control creation. I decided to put OpenGL initialization code just after the control subclassing operation:

//
// OnHandleCreate
//
void OnHandleCreated(EventArgs* e)
{
    System::Diagnostics::Debug::Assert(m_pCtrl->GetSafeHwnd() == NULL);

    m_pCtrl->SubclassWindow((HWND)get_Handle().ToPointer());

    m_pCtrl->InitOpenGL();	// Contains all the common OpenGL initialization functions calls
            
    Control::OnHandleCreated(e);
}
The following is the InitOpenGL function body:
//
// InitOpenGL
//
int COpenglWnd::InitOpenGL(void)
{

    CClientDC dc(this);

    //
    // Fill in the Pixel Format Descriptor
    //
    PIXELFORMATDESCRIPTOR pfd;
    memset(&pfd,0, sizeof(PIXELFORMATDESCRIPTOR));

    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);   
    pfd.nVersion = 1 ;                           // Version number
    pfd.dwFlags =  PFD_DOUBLEBUFFER |            // Use double buffer
                   PFD_SUPPORT_OPENGL |          // Use OpenGL
                   PFD_DRAW_TO_WINDOW;           // Pixel format is for a window.
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;                         // 8-bit color
    pfd.cDepthBits = 32;                         // 32-bit depth buffer
    pfd.iLayerType = PFD_MAIN_PLANE;             // Layer type

    int nPixelFormat = ChoosePixelFormat(dc.m_hDC, &pfd);

    if (nPixelFormat == 0) {
        TRACE("ChoosePixelFormat Failed %d\r\n",GetLastError());
        return -1;
    }

    TRACE("Pixel Format %d\r\n", nPixelFormat);

    BOOL bResult = SetPixelFormat(dc.m_hDC, nPixelFormat, &pfd);
    if (!bResult) {
        TRACE("SetPixelFormat Failed %d\r\n",GetLastError());
        return -1;
    }
    
    //
    // Create a rendering context.
    //
    m_hrc = wglCreateContext(dc.m_hDC);
    if (!m_hrc) {
        TRACE("wglCreateContext Failed %x\r\n", GetLastError()) ;
        return -1;
    }

    PrepareScene();

    return 0;
}

It was also easy to add some Properties to play with graphics in design view. If you look in the OpenGLScene control properties you can find some fields that allow you to modify the scene on the fly:

Properties

Remarks

Unfortunately, as you can read on the Rama's article, there does exist a problem with the "Copy local" flag of the openglscene.dll reference. Has to be set to "false" to work in design view and to "true" to run the application. We are still looking for the reason of this strange behaviour.

Summary

Personally I find this workaround the best way to work with C# and OpenGL without waiting for an "official" approach. Allows you to put as many OpenGL controls as you want on your .NET windows Form and easily interact with them.

You can start your first C# OpenGL application simply using the code provided with this article.




Letyshops [lifetime]