VR-Forces 5.0.3 Developer's Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
exampleMFC

Table of Contents

Overview

This example shows how to embed a VR-Vantage window in an MFC application.

Expected Result

exampleMFC2.png
example MFC Result

Example details

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:

myDe = new makVrv::DtDe();

It then calls a helper function, initMfc(), which registers the window creators:

initMfc();

InitInstance() then registers the OSG plugin:

It creates the main window by calling the helper function createMainWindow():

createMainWindow();

It initializes the display engine with a display engine initializer created by makeDeInitializer() (see below):

myDe->setDeInitializer(initializer);
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():

virtual int 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:

else
{
ExampleMFCApp::Tick();
}

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()):

makVrv::DtDeInitializer makeDeInitializer()

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";
makVrv::DtObserverConfiguration observerConfig(observerName);

It then creates a channel configuration, and tells it to use the observer configuration created above:

channel.setObserverName(observerName);

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";
makVrv::DtDisplayConfiguration displayConfig(displayName);
displayConfig.windowConfigurations().add(windowConfig);

An input driver configuration is created next:

inputConfig.setOptionalParameter( "windowDependent", "true" );
inputConfig.observerConfigurations().add(observerConfig);

Now that a display configuration and input driver configuration exist, they are used to create a display engine initializer, which is then returned:

void initMfc()

initMfc() registers creators for the main window (DtMfcMainWindow, derived from CFrameWnd and DtDeMainWindow):

and the embedded OSG window (DtEmbeddedMfcOsgWindow, derived from CWnd and DtOsgWindow):

void createMainWindow()

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):

windowProvider.igMainWindow();

void Tick()

Tick() calls DtTimedSection's stop() method to recalculate the time the application has run

myTimer->stop();

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:

ExampleMFCApp theApp;

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 ./bin64/exampleMFC.exe (on Windows) or ./bin64/exampleMFC (on Linux). For more information about running examples, please see Running Applications and Examples.

Example Source Files


exampleMFC.cxx

/******************************************************************************
* Copyright (c) 2022 MAK Technologies, Inc.
* All rights reserved.
******************************************************************************/
#include <afxwin.h>
#include "MFCClasses.h"
// Additional libraries to load for handling terrain databases
// Includes needed to load a terrain and set up an ocean
#include <matrix/vlMath.h>
// Note : to compile with Visual Studio 2013 you may need to install
// the missing multi byte MFC library found here https://www.microsoft.com/en-us/download/details.aspx?id=40770
class ExampleMFCApp : public CWinApp
{
public:
virtual BOOL InitInstance()
{
//Make the main Display Engine object.
myDe = new makVrv::DtDe();
//Register the Mfc classes.
initMfc();
//Register the osg module.
// Register additional modules for managing terrains
// Register module for dynamic ocean
//Create the Main Window.
createMainWindow();
makVrv::DtDeInitializer initializer = makeDeInitializer();
//create the log once we get the DeInitializer since we need this as early as possible
myDe->createDebugLog(initializer.logFileName(), initializer.notifyLevel());
//Initialize the De.
myDe->setDeInitializer(initializer);
myDe->initialize();
//Make time for getting system time.
myTimer = new DtTimedSection;
//Finish init.
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
{
ExampleMFCApp::Tick();
}
}
}
virtual ~ExampleMFCApp()
{
delete myDe;
delete myTimer;
}
protected:
makVrv::DtDeInitializer makeDeInitializer()
{
// Configure an observer for channel control
std::string observerName = "Observer 1";
makVrv::DtObserverConfiguration observerConfig(observerName);
// Create a single channel for the observer
channel.setObserverName(observerName);
// Place the channel in a embedded window.
windowConfig.channelConfigurations().add(channel);
// Add the window to the display config.
std::string displayName = "Example VR-Vantage Embedded in MFC App";
makVrv::DtDisplayConfiguration displayConfig(displayName);
displayConfig.windowConfigurations().add(windowConfig);
// Create an input configuration.
inputConfig.setOptionalParameter( "windowDependent", "true" );
inputConfig.observerConfigurations().add(observerConfig);
//Default initializer
init.deConfiguration().displayConfigurations().add(displayConfig);
init.setDisplayEngineName(displayName);
init.setInputDriverConfiguration( inputConfig );
return init;
}
void initMfc()
{
//Set the main window provider instance.
//Set the embedded window creator.
}
void createMainWindow()
{
// Get the DtDeMainWindowProvider,
// and create the DtDeMainWindow
makVrv::DtDeMainWindowProvider& windowProvider =
// Causes creation of main window
windowProvider.igMainWindow();
}
void Tick()
{
static bool firstT = true;
//Stop to recalculate duration since start.
myTimer->stop();
myDe->tick(myTimer->duration());
if ( firstT )
{
firstT = false;
makVrv::DtScene& sceneDriver = myDe->scene();
std::string groundDbPath = myDe->dePathConfiguration().sharedDataPath();
groundDbPath += "/TerrainData/TerrainConfiguration/Ground_DB II.mtf";
if ( sceneDriver.terrainFileName() != groundDbPath )
{
sceneDriver.loadTerrain( groundDbPath );
// add an ocean layer - this can be saved with the database in an mtf file
sceneDriver.terrain().addOceanLayer("Ocean");
// set the sea level to 10 m since this database has water polygons instead
// of bathymetry
makVrv::DtOceanLayer* layer = sceneDriver.terrain().findOceanLayer( "Ocean" );
layer->setSeaLevel( 10. );
// ---- set the sea state
// Put sea state in manual mode ( otherwise, its driven by the wind speed / direction )
sceneDriver.environment().setWindDrivenSeaState( false );
// Now we can manually set sea state and direction
sceneDriver.environment().setSeaStateDirection( DtDeg2Rad(90.) ); // east
sceneDriver.environment().setSeaChoppiness( 0.8 ); // 0.- 1.
}
// Start over the ocean
myDe->driverManager().inputDriver().currentObserver()->setLocation( 0., 0., 100. );
}
}
protected:
makVrv::DtDe* myDe;
DtTimedSection* myTimer;
};
ExampleMFCApp theApp;

MFCClasses.h

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#ifndef MFCClasses_H
#define MFCClasses_H
#include <afxwin.h>
#include <GL/GL.h>
#include <osg/GraphicsContext>
#include <osgViewer/GraphicsWindow>
#include <vlutil/vlPerformanceStats.h>
#include <vrvCore/DtDe.h>
#include <vrvOsg/vrvOsg.h>
{
public:
//DtDeMainWindow Interface
virtual void setApplicationTitle(const std::string& appName);
virtual std::string DtMfcMainWindow::applicationTitle() const;
virtual void setApplicationIcon(const std::string& iconName);
virtual void setShowQuitDialogOnClose(bool value);
virtual void destroyWindow();
virtual void quit();
protected:
};
{
public:
virtual bool isValid() const;
virtual void setPosition(int x,int y);
virtual void resize(int width,int height);
virtual void sizeChanged(int width,int height);
//Create the OpenGL Window
void oglCreate(CRect rect, CWnd *parent);
void oglInitialize(bool doubleBuffer, bool stereo, unsigned int colorBits,
unsigned int depthBits, unsigned int stencilBits, bool vsync);
void oglClose();
bool makeCurrent();
bool release();
void swapBuffers();
void setVSync(bool enabled);
// Added message classes:
afx_msg void OnPaint();
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnDraw(CDC *pDC);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMButtonDown(UINT nFlags, CPoint point);
afx_msg void OnMButtonUp(UINT nFlags, CPoint point);
DECLARE_MESSAGE_MAP()
private:
HDC myHDC;
HGLRC myHGLRC;
};
class DtEmbeddedMfcOsgWindowCreator : public makVrv::DtWindowCreator
{
public:
virtual makVrv::DtWindow* create(makVrv::DtDe& de,
};
class DtMfcControlAsOsgContext : public osgViewer::GraphicsWindowEmbedded
{
public:
DtEmbeddedMfcOsgWindow* wnd, osg::GraphicsContext::Traits* traits);
virtual bool valid() const;
virtual bool realizeImplementation();
virtual bool isRealizedImplementation() const;
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:
virtual makVrv::DtDeMainWindow* createMainWindow(makVrv::DtDe& de);
};
#endif

MFCClasses.cxx

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include "MFCClasses.h"
: DtDeMainWindow(de)
, myShowQuitFlag(false)
{
Create(NULL, "VR-Vantage MFC Example");
}
//DtDeMainWindow Interface
void DtMfcMainWindow::setApplicationTitle(const std::string& appName)
{
this->SetWindowText(appName.c_str());
}
{
CString cstr;
this->GetWindowText(cstr);
return std::string(cstr);
}
void DtMfcMainWindow::setApplicationIcon(const std::string& iconName)
{
HANDLE image = LoadImage(AfxGetInstanceHandle(),iconName.c_str(),
IMAGE_ICON,16,16,LR_LOADFROMFILE | LR_DEFAULTSIZE);
if(image != NULL)
{
this->SetIcon((HICON)image,FALSE);
}
}
{
myShowQuitFlag = value;
}
{
this->CloseWindow();
}
{
this->SendMessage(WM_QUIT);
}
osg::GraphicsContext::Traits* traits)
: osgViewer::GraphicsWindowEmbedded(traits)
, myControl(wnd)
, myDe( de )
{
}
{
return true;
}
{
myControl->oglInitialize(_traits->doubleBuffer,
_traits->quadBufferStereo,
_traits->red + _traits->green + _traits->blue + _traits->alpha,
_traits->depth,
_traits->stencil,
_traits->vsync);
return true;
}
{
}
{
}
{
myControl->GetFocus();
}
{
}
{
{
}
}
{
return myControl->release();
}
{
return myControl->swapBuffers();
}
{
}
{
}
: 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();
myControl = new DtMfcControlAsOsgContext(de,this,traits.get());
myContext = myControl;
DtMfcMainWindow* mainWindow = dynamic_cast<DtMfcMainWindow*>(&
if(mainWindow)
{
//Create the window based on the size of the main Window.
RECT bounds;
mainWindow->GetClientRect(&bounds);
oglCreate(bounds, mainWindow);
}
}
{
myControl = 0;
}
BEGIN_MESSAGE_MAP(DtEmbeddedMfcOsgWindow, CWnd)
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()
bool DtEmbeddedMfcOsgWindow::isValid() const
{
//Assume always valid
return true;
}
{
//Typically you can't set position of embedded window
//Do Nothing
}
void DtEmbeddedMfcOsgWindow::resize(int width,int height)
{
//Typically you can't set position of embedded window
//Do Nothing
}
void DtEmbeddedMfcOsgWindow::sizeChanged(int width,int height)
{
}
{
return (myHDC != 0);
}
void DtEmbeddedMfcOsgWindow::oglCreate(CRect rect, CWnd *parent)
{
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);
myHWnd = parent;
}
{
//CPaintDC dc(this); // device context for painting
ValidateRect(NULL);
}
void DtEmbeddedMfcOsgWindow::OnMouseMove( UINT nFlags, CPoint point )
{
myControl->getEventQueue()->mouseMotion(point.x,point.y);
}
void DtEmbeddedMfcOsgWindow::OnLButtonDown( UINT nFlags, CPoint point )
{
myControl->getEventQueue()->mouseButtonPress(point.x,point.y,1);
}
void DtEmbeddedMfcOsgWindow::OnLButtonUp( UINT nFlags, CPoint point )
{
myControl->getEventQueue()->mouseButtonRelease(point.x,point.y,1);
}
void DtEmbeddedMfcOsgWindow::OnRButtonDown( UINT nFlags, CPoint point )
{
myControl->getEventQueue()->mouseButtonPress(point.x,point.y,3);
}
void DtEmbeddedMfcOsgWindow::OnRButtonUp( UINT nFlags, CPoint point )
{
myControl->getEventQueue()->mouseButtonRelease(point.x,point.y,3);
}
void DtEmbeddedMfcOsgWindow::OnMButtonDown( UINT nFlags, CPoint point )
{
myControl->getEventQueue()->mouseButtonPress(point.x,point.y,2);
}
void DtEmbeddedMfcOsgWindow::OnMButtonUp( UINT nFlags, CPoint point )
{
myControl->getEventQueue()->mouseButtonRelease(point.x,point.y,2);
}
int DtEmbeddedMfcOsgWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
return 0;
}
void DtEmbeddedMfcOsgWindow::oglInitialize(bool doubleBuffer, bool stereo,
unsigned int color,
unsigned int depth,
unsigned int stencil,
bool vsync)
{
// Initial Setup:
//
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 ;
// Get device context only once.
myHDC = GetDC()->m_hDC;
// Pixel format.
myPixelFormat = ChoosePixelFormat(myHDC, &pfd);
SetPixelFormat(myHDC, myPixelFormat, &pfd);
// Create the OpenGL Rendering Context.
myHGLRC = wglCreateContext(myHDC);
wglMakeCurrent(myHDC, myHGLRC);
setVSync(vsync);
}
{
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; // Error: WGL_EXT_swap_control extension not supported on your computer.\n");
else
{
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
if( wglSwapIntervalEXT )
{
wglSwapIntervalEXT(enabled ? 1 : 0);
}
}
}
{
wglDeleteContext(myHGLRC);
myHGLRC = 0;
myHDC = 0;
}
void DtEmbeddedMfcOsgWindow::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
int width = cx;
int height = cy;
myControl->getEventQueue()->windowResize(0, 0, width, height);
myControl->resized(0,0,width,height);
}
{
return wglMakeCurrent(myHDC,myHGLRC) == TRUE;
}
{
return wglMakeCurrent(myHDC,0) == TRUE;
}
{
SwapBuffers(myHDC);
}
: DtDeMainWindowProvider(de)
{
myDestroyMainWindowFlag = false;
}
{
DtMfcMainWindow* window = new DtMfcMainWindow(de);
window->ShowWindow(1);
AfxGetApp()->m_pMainWnd = window;
return window;
}
{
return new DtEmbeddedMfcOsgWindow(de,config);
}

[<< Examples] [Home] [Top of Page]


Document ID: Generated on Thu Jun 1 17:58:13 EDT 2023 from SVN revision 255404
Copyright © 2005-2021 MAK Technologies. All Rights Reserved (www.mak.com)