-
Notifications
You must be signed in to change notification settings - Fork 116
Using Coin with MFC and VisualC++
You are here: Home → Documentation → Windows information page → Tutorials → Using Coin with MFC and Visual C++
This tutorial will show you how to create a Windows application based on Coin, using Visual C++ and the Microsoft Foundation Classes (MFC) class library.
- Start Visual C++. This tutorial is based on Visual C++ 6.0. No service pack is required, but it is recommended that you use the latest service pack from Microsoft.
- Create a new project. File | New | Projects | MFC AppWizard (exe).
This tutorial assumes the project name is "MFCViewer". Use the
default parameters for the wizard, but note the following
- Make sure you create an MDI application (Multiple Document Interface) with Document/View Architecture support.
- Please refer to Tutorial - Part 1 - Microsoft Visual Studio Project Settings on how to integrate the Coin3D libraries with your project.
Add this line to the list of #includes:
#include <Inventor/Win/SoWin.h>
Edit the function CMFCViewerApp::InitInstance() so that the first line is
SoWin::init("");
This will init the SoWin library and the Coin library, and must be called before any use of Coin or SoWin.
Add the following lines to the list of #includes (below the precompiled headers - #ifdef/#pragma once/#endif sequence):
#include <Inventor/Win/SoWin.h>
#include <Inventor/Win/viewers/SoWinExaminerViewer.h>
Add the public data member
SoWinExaminerViewer * viewer;
The ExaminerViewer gives us a place to render our scenegraph, as well as interacting with whatever is displayed (like rotating it, selecting parts of the scenegraph, etc)
Modify the constructor so that it looks like this:
CMFCViewerView::CMFCViewerView()
{
viewer = NULL;
}
Modify the destructor so that it looks like this:
CMFCViewerView::CMFCViewerView()
{
if (viewer != NULL)
delete viewer;
}
Modify the method CMFCViewerView::OnDraw(CDC* pDC) so that it looks like this:
void CMFCViewerView::OnDraw(CDC* pDC)
{
CMFCViewerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (viewer == NULL)
{
viewer = new SoWinExaminerViewer( m_hWnd );
viewer->setDecoration(FALSE);
WINDOWPLACEMENT p;
memset(&p, 0, sizeof(p));
p.length = sizeof(WINDOWPLACEMENT);
p.showCmd = SW_SHOWMAXIMIZED;
SetWindowPlacement(&p);
}
}
This will embed the ExaminerViewer in the CMFCViewerView window. Decoration is turned off.
If you wondered what that last sentence meant, try doing viewer->setDecoration(TRUE); instead. You can also turn decoration on and off by right-clicking in the ExaminerViewer window while the application is running.
Just to get something to look at (make sure you undo these changes before the next step): Add the following lines to the list of #includes:
#include <Inventor/nodes/SoSeparator.h> // remove me later
#include <Inventor/nodes/SoCone.h> // remove me later
Modify the method CMFCViewerView::OnDraw(CDC* pDC) so that it looks like this
void CMFCViewerView::OnDraw(CDC* pDC)
{
CMFCViewerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (viewer == NULL)
{
viewer = new SoWinExaminerViewer( m_hWnd );
viewer->setDecoration(FALSE);
SoSeparator *root = new SoSeparator; // remove me later
root->addChild(new SoCone); // remove me later
viewer->setSceneGraph(root); // remove me later
}
}
Build the project and run. You should see a standard MFC MDI application with one window containing a rather dull looking cone.
Take the cone for a spin (hint: try the mouse)
Remember to delete the lines marked "~/~/ remove me later" before moving on to the next step of this tutorial
In this section we'll create a default scenegraph used when the users creates a new document (File | New). This is included just to let you get a feel for how to create a scenegraph using Coin.
Add the following line somewhere above the CMFCViewerDoc class definition:
class SoSeparator;
This informs the compiler that we're going to use a class called SoSeparator.
Add a public data member to the CMFCViewerDoc class:
SoSeparator *root;
This is the topmost node in our scenegraph.
Add the following lines to the list of #includes:
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoCone.h>
#include <Inventor/nodes/SoTranslation.h>
#include <Inventor/nodes/SoText2.h>
These are the nodes we are going to use in our scenegraph, and we have to include the header file for each node.
Modify the method OnNewDocument() so that it looks like this:
BOOL CMFCViewerDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
root = new SoSeparator;
root->ref();
SoMaterial *myMaterial;
root->addChild(myMaterial = new SoMaterial);
myMaterial->diffuseColor.setValue(1.0, 0.0, 0.0);
root->addChild(new SoCone);
SoSeparator * instructsep = new SoSeparator;
root->addChild(instructsep);
instructsep->addChild(myMaterial = new SoMaterial);
myMaterial->diffuseColor.setValue(0.5, 1.0, 1.0);
SoTranslation * instructtrans = new SoTranslation;
instructtrans->translation = SbVec3f(-2.0f, 1.3f, 2.0f);
instructsep->addChild(instructtrans);
SoText2 * instructions = new SoText2;
const char * str[] = {
"Instructions for the MFCViewer tutorial",
"",
"Left mouse button = rotate",
"Middle mouse button = move",
"CTRL + middle mouse button = zoom",
"Right mouse button = options"
};
instructions->string.setValues(0, sizeof(str) / sizeof(char *), str);
instructions->justification = SoText2::LEFT;
instructsep->addChild(instructions);
return TRUE;
}
The scenegraph is built by adding children to the root node. Remember that Coin takes care of deleting all scenegraph objects, so there's no need for the application programmer to remember any pointers to these objects and delete them afterwards (in fact, it would be an error to do so). This is done by a technique known as reference counting, and the call to root->ref(); above makes sure Coin does not try to delete the root node or any of it's children.
Modify the constructor and destructor so that they look like this:
CMFCViewerDoc::CMFCViewerDoc()
{
root = NULL;
}
CMFCViewerDoc::~CMFCViewerDoc()
{
if (root)
root->unref();
}
The call to root->unref(); tells Coin that we're not using the root node anymore, so it's OK for us if Coin wants to delete it.
Add the following line to the list of #includes:
#include <Inventor/nodes/SoSeparator.h>
Modify the method CMFCViewerView::OnDraw(CDC* pDC) so that it looks like this:
void CMFCViewerView::OnDraw(CDC* pDC)
{
CMFCViewerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (viewer == NULL)
{
viewer = new SoWinExaminerViewer( m_hWnd );
viewer->setDecoration(FALSE);
SoSeparator *root = GetDocument()->root;
viewer->setSceneGraph(root);
}
}
We've now modified the OnDraw method so that it gets the root of the scenegraph from the document object.
Compile and run the project. The application should start with one window open, which shows the scenegraph we've just created.
Well, that's the end of the tutorial. By now you should have a feel for how to integrate Coin with applications written in MFC, and how to create your own scenegraph.