This example shows how to embed a VR-Vantage window in an MFC application.
All MFC applications create a class that derives from CWinApp, and overrides its InitInstance() and Run() methods as well as its virtual destructor to initialize, run, and tear down the application.
Declare ExampleMFCApp, which derives from CWinApp:
class ExampleMFCApp : public CWinApp
The first CWinApp method overridden is InitInstance():
virtual BOOL InitInstance()
It creates tbe VR-Vantage display engine:
It then calls a helper function, initMfc(), which registers the window creators:
InitInstance() then registers the OSG plugin:
It creates the main window by calling the helper function createMainWindow():
It initializes the display engine with a display engine initializer created by makeDeInitializer() (see below):
myDe->setDeInitializer(makeDeInitializer());
myDe->initialize();
InitInstance() the creates a DtTimedSection to track frame time during the Tick() function (see below):
myTimer = new DtTimedSection;
And finally, calls and returns the result of the base class InitInstance() method:
return CWinApp::InitInstance();
The other CWinApp method overridden is Run():
Run() needs to manage Windows messages. If a message exists, it calls PumpMessage(); and if PumpMessage() fails, the instance is terminated:
_AFX_THREAD_STATE* pState = AfxGetThreadState();
for(;;)
{
if (PeekMessage(&(pState->m_msgCur) , NULL , 0, 0, PM_NOREMOVE))
{
if (!PumpMessage())
{
return ExitInstance();
It calls the Tick() method when there are no Windows messages to process:
ExampleMFCApp also overrides CWinApp's virtual destructor so that it can delete the objects created at initialization:
virtual ~ExampleMFCApp()
{
delete myDe;
delete myTimer;
}
The following helper methods are defined (and called from InitInstance() or Run()):
makeDeInitializer sets up all the configuration information needed for the VR-Vantage display engine. It first creates an observer configuration specifying a name and using the defaults for all other observer parameters:
std::string observerName = "Observer 1";
It then creates a channel configuration, and tells it to use the observer configuration created above:
Next, it creates a window configuration, and tells it to be an embedded window and to use the channel configuration created above:
Then a display configuration is created, using the window configuration created above:
std::string displayName = "Example VR-Vantage Embedded in MFC App";
displayConfig.windowConfigurations().add(windowConfig);
An input driver configuration is created next:
Now that a display configuration and input driver configuration exist, they are used to create a display engine initializer, which is then returned:
initMfc() registers creators for the main window (DtMfcMainWindow, derived from CFrameWnd and DtDeMainWindow):
and the embedded OSG window (DtEmbeddedMfcOsgWindow, derived from CWnd and DtOsgWindow):
createMainWindow() gets the window provider:
and then creates the new DtMfcMainWindow by calling the window provider's igMainWindow() accessor (which creates the main window since it doesn't yet exist):
Tick() calls DtTimedSection's stop() method to recalculate the time the application has run
and then calls the Display Engine's tick method with the DtTimedSection's duration() as its argument:
myDe->tick(myTimer->duration());
Finally, an instance of the derived application class must be created with global scope:
Building the Example
VR-Vantage includes pre-built versions of the example application. To build it yourself, follow the instructions at Building VR-Vantage Examples, Applications, and Plug-ins.
Running the Example
This example is an application. You can run it by running ./bin/exampleMFCpage.exe (on Windows) or ./bin/exampleMFCpage (on Linux). For more information about running examples, please see Running Applications and Examples.
Example Source Files
exampleMFC.cxx
#include <afxwin.h>
class ExampleMFCApp : public CWinApp
{
public:
virtual BOOL InitInstance()
{
initMfc();
createMainWindow();
myDe->setDeInitializer(makeDeInitializer());
myDe->initialize();
myTimer = new DtTimedSection;
return CWinApp::InitInstance();
}
virtual int Run()
{
_AFX_THREAD_STATE* pState = AfxGetThreadState();
for(;;)
{
if (PeekMessage(&(pState->m_msgCur) , NULL , 0, 0, PM_NOREMOVE))
{
if (!PumpMessage())
{
return ExitInstance();
}
}
else
{
Tick();
}
}
}
virtual ~ExampleMFCApp()
{
delete myDe;
delete myTimer;
}
protected:
{
std::string observerName = "Observer 1";
std::string displayName = "Example VR-Vantage Embedded in MFC App";
displayConfig.windowConfigurations().add(windowConfig);
}
void initMfc()
{
}
void createMainWindow()
{
}
void Tick()
{
myTimer->stop();
myDe->tick(myTimer->duration());
}
protected:
DtTimedSection* myTimer;
};
ExampleMFCApp theApp;
MFCClasses.h
#ifndef MFCClasses_H
#define MFCClasses_H
#include <afxwin.h>
#include <GL/GL.h>
#include <osg/GraphicsContext>
#include <osgViewer/GraphicsWindow>
#include <vlutil/vlPerformanceStats.h>
{
public:
protected:
};
{
public:
void oglInitialize(
bool doubleBuffer,
bool stereo,
unsigned int colorBits,
unsigned int depthBits, unsigned int stencilBits, bool vsync);
afx_msg
void OnSize(UINT nType,
int cx,
int cy);
afx_msg
void OnDraw(CDC *pDC);
afx_msg
int OnCreate(LPCREATESTRUCT lpCreateStruct);
DECLARE_MESSAGE_MAP()
private:
};
{
public:
};
{
public:
virtual bool valid() const;
virtual bool realizeImplementation();
virtual void closeImplementation();
virtual void grabFocus();
virtual void grabFocusIfPointerInWindow();
virtual bool makeCurrentImplementation();
virtual bool releaseContextImplementation();
virtual void swapBuffersImplementation();
virtual void requestWarpPointer( float x, float y );
virtual void useCursor( bool onOff );
protected:
};
{
public:
protected:
};
#endif
MFCClasses.cxx
: DtDeMainWindow(de)
{
Create(NULL, "VR-Vantage MFC Example");
}
{
this->SetWindowText(appName.c_str());
}
{
CString cstr;
this->GetWindowText(cstr);
return std::string(cstr);
}
{
HANDLE image = LoadImage(AfxGetInstanceHandle(),iconName.c_str(),
IMAGE_ICON,16,16,LR_LOADFROMFILE | LR_DEFAULTSIZE);
if(image != NULL)
{
this->SetIcon((HICON)image,FALSE);
}
}
{
}
{
this->CloseWindow();
}
{
this->SendMessage(WM_QUIT);
}
osg::GraphicsContext::Traits* traits)
, myControl(wnd)
, myDe( de )
{
}
{
return true;
}
{
_traits->quadBufferStereo,
_traits->red + _traits->green + _traits->blue + _traits->alpha,
_traits->depth,
_traits->stencil,
_traits->vsync);
return true;
}
{
}
{
}
{
}
{
}
{
{
}
}
{
}
{
}
{
}
{
}
: DtOsgWindow(de,wc)
, myControl(0)
, myHWnd(0)
, myHDC(0)
, myHGLRC(0)
, myPixelFormat(0)
{
osg::ref_ptr<osg::GraphicsContext::Traits> traits = DtOsgWindow::createDefaultTraits();
traits->x = 0;
traits->y = 0;
traits->doubleBuffer = myDe.deInitializer().doubleBuffer();
traits->vsync = myDe.deInitializer().vsync();
traits->width = 0;
traits->height = 0;
traits->windowName = myWindowConfiguration.name();
myContext = myControl;
if(mainWindow)
{
RECT bounds;
mainWindow->GetClientRect(&bounds);
oglCreate(bounds, mainWindow);
}
}
{
}
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_CREATE()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_RBUTTONDOWN()
ON_WM_RBUTTONUP()
ON_WM_MBUTTONDOWN()
ON_WM_MBUTTONUP()
END_MESSAGE_MAP()
{
return true;
}
{
}
{
}
{
}
{
}
{
CString className = AfxRegisterWndClass(
CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
NULL,
(HBRUSH)GetStockObject(BLACK_BRUSH), NULL);
CreateEx(0, className, "OpenGL", WS_CHILD | WS_VISIBLE |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN, rect, parent, 0);
}
{
ValidateRect(NULL);
}
{
myControl->getEventQueue()->mouseMotion(point.x,point.y);
}
{
myControl->getEventQueue()->mouseButtonPress(point.x,point.y,1);
}
{
myControl->getEventQueue()->mouseButtonRelease(point.x,point.y,1);
}
{
myControl->getEventQueue()->mouseButtonPress(point.x,point.y,3);
}
{
myControl->getEventQueue()->mouseButtonRelease(point.x,point.y,3);
}
{
myControl->getEventQueue()->mouseButtonPress(point.x,point.y,2);
}
{
myControl->getEventQueue()->mouseButtonRelease(point.x,point.y,2);
}
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
return 0;
}
unsigned int color,
unsigned int depth,
unsigned int stencil,
bool vsync)
{
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)) ;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1 ;
pfd.dwFlags = PFD_DOUBLEBUFFER |
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW ;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = color;
pfd.cDepthBits = depth;
pfd.cStencilBits = stencil;
pfd.iLayerType = PFD_MAIN_PLANE ;
}
{
typedef BOOL (APIENTRY *PFNWGLSWAPINTERVALFARPROC)(
int );
PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = 0;
const char *extensions = (const char*)glGetString( GL_EXTENSIONS );
if( strstr( extensions, "WGL_EXT_swap_control" ) == 0 )
return;
else
{
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
if( wglSwapIntervalEXT )
{
wglSwapIntervalEXT(enabled ? 1 : 0);
}
}
}
{
}
{
myControl->getEventQueue()->windowResize(0, 0, width, height);
}
{
}
{
return wglMakeCurrent(
myHDC,0) == TRUE;
}
{
}
: DtDeMainWindowProvider(de)
{
}
{
window->ShowWindow(1);
AfxGetApp()->m_pMainWnd = window;
return window;
}
{
}