2. Embedding VglTools in Application Frameworks

VglTools Programmer Manual

Graphics libraries generally communicate intimately with the application framework. There is a need to draw multiple views in application defined windows and interact in an application specific way to user input.

2.1 Embedded, In-Window, Applications

This example illustrates how one connects an OpenGLDev object to an existing window. This process is typical of building component applications (such as finite element analysis systems) which are designed to be embedded in a host application (such as a CAD system). In this case, the host application provides a handle to the window system and a callback when graphics primtives generated by the embedded application are meant to be drawn. Usually the lighting and transformations are set by the host application and the embedded application provides 3D graphics primitives and attributes.
       vgl_OpenGLDev  *opengldev;
       vgl_DrawFun *dfdev;
       Vint iparam;
    
                       /* Once at the beginning */ 
                       /* a class method */ 
       vgl_OpenGLDevConnectWIN ();
    
                       /* create drawing functions */
       dfdev = vgl_DrawFunBegin();
    
                       /* create device objects and load drawing functions */
       opengldev = vgl_OpenGLDevBegin();
       vgl_OpenGLDevDrawFun (opengldev,dfdev);
    
                       /* use current graphics context of application */ 
       iparam = VGL_ON;
       vgl_DrawFunConfigureWindow (dfdev,VGL_WINDOWUSECONTEXT,&iparam);
                       /* connect to given Window window handle */ 
       vgl_DrawFunConnectWindow (dfdev,hWnd);
    
    ...
    
                       /* Now each time you need to draw to the window */ 
       vgl_DrawFunConfigureWindow (dfdev,VGL_WINDOWSTATEINIT,NULL);
    
                       /* all drawing occurs here */ 
    .
    .
    .
    
    
                       /* when all drawing is complete */ 
       vgl_DrawFunConfigureWindow (dfdev,VGL_WINDOWSTATETERM,NULL);
    ...
                       /* Once at the end */ 
                       /* disconnect from window */ 
       vgl_DrawFunDisconnectWindow (dfdev);
    
                       /* destroy objects */ 
       vgl_OpenGLDevEnd (opengldev);
       vgl_DrawFunEnd (dfdev);
    
                       /* disconnect from window system */ 
       vgl_OpenGLDevDisconnect ();
    


2.2 Creating a Simple Microsoft MFC Application

This example illustrates how to use VglTools with Microsoft's MFC class library. The example shows the modifications required to the default application view files. In addition to the default message handlers for OnDraw and PreCreateWindow, it is necessary to add functions for the following messages:
  • WM_CREATE for OnCreate
  • WM_DESTROY for OnDestroy
  • WM_ERASEBACKGROUND for OnEraseBkgnd
  • WM_SIZE for OnSize
The MFC application uses OpenGL to draw "Hello World" in the window. By using an OpenGLDev object and a DrawFun object, very little OpenGL specific code needs to be written.


Figure 1-3, Output from a Simple Microsoft MFC Application

2.2.1 Editing VglView.h

The editing required in the VglView.h file involves adding VglTools specific include files and two protected data members: pointers to an OpenGLDev object and a DrawFun object.
    //
    //          VglTools includes
    //
    #include "base/base.h"
    #include "vgl/vgl.h"
     .
     .
    protected:
    //
    //          VglTools objects;
    //
       vgl_OpenGLDev *m_ogldev;
       vgl_DrawFun *m_dfdv;
    

2.2.2 Editing VglView.cpp

The editing required in the VglView.cpp file involves adding to the message handlers mentioned above as well as the class constructor, CVglView(), and destuctor, ~CVglView(). Only the code fragments needed to be added are shown below.

In the class constructor, CVglView(), connect the OpenGLDev module to Windows, instance OpenGLDev and DrawFun objects and load OpenGLDev drawing functions.

       vgl_OpenGLDevConnectWIN ();
       m_ogldev = vgl_OpenGLDevBegin ();
       m_dfdv = vgl_DrawFunBegin ();
       vgl_OpenGLDevDrawFun (m_ogldev,m_dfdv);
    

In the class destructor, ~CVglView(), destroy the OpenGLDev and DrawFun objects and disconnect the OpenGLDev module from Windows.

       vgl_OpenGLDevEnd (m_ogldev);
       vgl_DrawFunEnd (m_dfdv);
       vgl_OpenGLDevDisconnect ();
    

In PreCreateWindow, the OpenGL window must be created with the WS_CLIPSIBLINGS and WS_CLIPCHILDREN style. In addition, do not set the CS_PARENTDC bit.

       cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
    

In OnEraseBkgnd, since OpenGL will be erasing the background with a Clear drawing function, there is no reason for Windows to do it. This is done by commenting out the original return and returning with a 1 always.

    // return CView::OnEraseBkgnd(pDC);
       return 1;
    

In OnCreate, connect the MFC window, m_hWnd, to the OpenGL interface. At this point the MFC window should not be drawn to, wait for the first WM_SIZE message (OnSize function) before drawing.

       vgl_DrawFunConnectWindow(m_dfdv,(Vword)m_hWnd);
    

In OnDestroy, disconnect the MFC window from the OpenGL interface.

       vgl_DrawFunDisconnectWindow (m_dfdv);
    

In OnSize, inform the OpenGL interface that the window has been resized. This will occur when the MFC window initially assumes its original size and then any time the window is resized by the user. The call to vgl_DrawFunSetWindow is only needed if a multiple view interface is used and multiple instances of OpenGLDev objects (one for each view window) have been generated.

       vgl_DrawFunSetWindow (m_dfdv);
       vgl_DrawFunResize (m_dfdv);
    

In OnDraw, place the code necessary to render the scene. In this case we clear the background to blue and render "Hello World" in red anchored at the center of the screen. Call vgl_DrawFunSwap to swap the buffers. Again, the call to vgl_DrawFunSetWindow is only needed if a multiple view interface is used.

       Vfloat c[3];
       Vfloat x[3];
     .
     .
       vgl_DrawFunSetWindow (m_dfdv);
     .
     .
       c[0] = 0.; c[1] = 0.; c[2] = 1.;
       vgl_DrawFunBackColor (m_dfdv,c);
       vgl_DrawFunClear (m_dfdv);
       c[0] = 1.;  c[1] = 0.;  c[2] = 0.;
       vgl_DrawFunColor (m_dfdv,c);
       x[0] = 0.;  x[1] = 0.;  x[2] = 0.;
       vgl_DrawFunText (m_dfdv,x,"Hello World");
       vgl_DrawFunSwap (m_dfdv);
    

The source to this example resides in the files VglView.cpp and VglView.h in the exam directory.

    // VglView.cpp : implementation of the CVglView class
    //
    
    #include "stdafx.h"
    #include "Vgl.h"
    
    #include "VglDoc.h"
    #include "VglView.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    /////////////////////////////////////////////////////////////////////////////
    // CVglView
    
    IMPLEMENT_DYNCREATE(CVglView, CView)
    
    BEGIN_MESSAGE_MAP(CVglView, CView)
    	//{{AFX_MSG_MAP(CVglView)
    	ON_WM_CREATE()
    	ON_WM_DESTROY()
    	ON_WM_SIZE()
    	ON_WM_ERASEBKGND()
    	//}}AFX_MSG_MAP
    	// Standard printing commands
    	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
    	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
    	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    // CVglView construction/destruction
    
    CVglView::CVglView()
    {
    	// TODO: add construction code here
    //
    //          Connect to Win32 and instance Vgl objects
    //
    	vgl_OpenGLDevConnectWIN ();
    	m_ogldev = vgl_OpenGLDevBegin ();
    	m_dfdv = vgl_DrawFunBegin ();
    	vgl_OpenGLDevDrawFun (m_ogldev,m_dfdv);
    }
    
    CVglView::~CVglView()
    {
    //
    //          Destroy objects and disconnect from Win32
    //
    	vgl_OpenGLDevEnd (m_ogldev);
    	vgl_DrawFunEnd (m_dfdv);
    	vgl_OpenGLDevDisconnect ();
    }
    
    BOOL CVglView::PreCreateWindow(CREATESTRUCT& cs)
    {
    	// TODO: Modify the Window class or styles here by modifying
    	//  the CREATESTRUCT cs
    
    //
    //          OpenGL window must be created with the following flags
    //
    	cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
    	return CView::PreCreateWindow(cs);
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // CVglView drawing
    
    void CVglView::OnDraw(CDC* pDC)
    {
    	Vfloat c[3];
    	Vfloat x[3];
    
    	CVglDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    
    	// TODO: add draw code for native data here
    //
    //          Make sure in a multiple view interface that drawing goes
    //          to the correct window.
    //
    	vgl_DrawFunSetWindow (m_dfdv);	
    //
    //          Draw Hello World
    //
    	c[0] = 0.; c[1] = 0.; c[2] = 1.;
    	vgl_DrawFunBackColor (m_dfdv,c);
    	vgl_DrawFunClear (m_dfdv);
    	c[0] = 1.;  c[1] = 0.;  c[2] = 0.;
    	vgl_DrawFunColor (m_dfdv,c);
    	x[0] = 0.;  x[1] = 0.;  x[2] = 0.;
    	vgl_DrawFunText (m_dfdv,x,"Hello World");
    	vgl_DrawFunSwap (m_dfdv);
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // CVglView printing
    
    BOOL CVglView::OnPreparePrinting(CPrintInfo* pInfo)
    {
    	// default preparation
    	return DoPreparePrinting(pInfo);
    }
    
    void CVglView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    	// TODO: add extra initialization before printing
    }
    
    void CVglView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    	// TODO: add cleanup after printing
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // CVglView diagnostics
    
    #ifdef _DEBUG
    void CVglView::AssertValid() const
    {
    	CView::AssertValid();
    }
    
    void CVglView::Dump(CDumpContext& dc) const
    {
    	CView::Dump(dc);
    }
    
    CVglDoc* CVglView::GetDocument() // non-debug version is inline
    {
    	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CVglDoc)));
    	return (CVglDoc*)m_pDocument;
    }
    #endif //_DEBUG
    
    /////////////////////////////////////////////////////////////////////////////
    // CVglView message handlers
    
    int CVglView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
    {
    	if (CView::OnCreate(lpCreateStruct) == -1)
    		return -1;
    	
    	// TODO: Add your specialized creation code here
    //
    //          Connect to MFC window
    //
    	vgl_DrawFunConnectWindow(m_dfdv,(Vword)m_hWnd);
    	return 0;
    }
    
    void CVglView::OnDestroy() 
    {
    	CView::OnDestroy();
    	
    	// TODO: Add your message handler code here
    //
    //          Disconnect from window
    //
    	vgl_DrawFunDisconnectWindow (m_dfdv);	
    }
    
    void CVglView::OnSize(UINT nType, int cx, int cy) 
    {
    	CView::OnSize(nType, cx, cy);
    	
    	// TODO: Add your message handler code here
    //
    //          Resize
    //
    	vgl_DrawFunSetWindow (m_dfdv);	
    	vgl_DrawFunResize (m_dfdv);
    }
    
    BOOL CVglView::OnEraseBkgnd(CDC* pDC) 
    {
    	// TODO: Add your message handler code here and/or call default
    //
    //          OpenGL will clear window, tell MFC not to
    //
    	
    //	return CView::OnEraseBkgnd(pDC);
    	return 1;
    }
    
    // VglView.h : interface of the CVglView class
    //
    /////////////////////////////////////////////////////////////////////////////
    
    #if !defined(AFX_VGLVIEW_H__93035A8C_7819_11D1_B2AA_0060979C3AE3__INCLUDED_)
    #define AFX_VGLVIEW_H__93035A8C_7819_11D1_B2AA_0060979C3AE3__INCLUDED_
    
    #if _MSC_VER >= 1000
    #pragma once
    #endif // _MSC_VER >= 1000
    //
    //          VglTools includes
    //
    #include "base/base.h"
    #include "vgl/vgl.h"
    
    class CVglView : public CView
    {
    protected: // create from serialization only
    	CVglView();
    	DECLARE_DYNCREATE(CVglView)
    
    // Attributes
    public:
    	CVglDoc* GetDocument();
    
    // Operations
    public:
    
    // Overrides
    	// ClassWizard generated virtual function overrides
    	//{{AFX_VIRTUAL(CVglView)
    	public:
    	virtual void OnDraw(CDC* pDC);  // overridden to draw this view
    	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
    	protected:
    	virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
    	virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
    	virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
    	//}}AFX_VIRTUAL
    
    // Implementation
    public:
    	virtual ~CVglView();
    #ifdef _DEBUG
    	virtual void AssertValid() const;
    	virtual void Dump(CDumpContext& dc) const;
    #endif
    
    protected:
    //
    //          VglTools objects;
    //
    	vgl_OpenGLDev *m_ogldev;
    	vgl_DrawFun *m_dfdv;
    
    // Generated message map functions
    protected:
    	//{{AFX_MSG(CVglView)
    	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    	afx_msg void OnDestroy();
    	afx_msg void OnSize(UINT nType, int cx, int cy);
    	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    	//}}AFX_MSG
    	DECLARE_MESSAGE_MAP()
    };
    
    #ifndef _DEBUG  // debug version in VglView.cpp
    inline CVglDoc* CVglView::GetDocument()
       { return (CVglDoc*)m_pDocument; }
    #endif
    
    /////////////////////////////////////////////////////////////////////////////
    
    //{{AFX_INSERT_LOCATION}}
    // Microsoft Developer Studio will insert additional declarations immediately before the previous line.
    
    #endif // !defined(AFX_VGLVIEW_H__93035A8C_7819_11D1_B2AA_0060979C3AE3__INCLUDED_)