2. Embedding VglTools in Application Frameworks
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
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_)