Skip to content

Using Coin with MFC and VisualC++

Volker Enderlein edited this page Dec 25, 2019 · 1 revision

You are here: HomeDocumentationWindows information pageTutorials → Using Coin with MFC and Visual C++

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.

Creating the project

  • 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.

Adding code for SoWin and Coin

Open the file MFCViewer.cpp

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.

Open the file MFCViewerView.h

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)

Open the file MFCViewerView.cpp

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

Creating a scenegraph

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.

Open the file MFCViewerDoc.h

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.

Open the file MFCViewerDoc.cpp

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.

Open the file MFCViewerView.cpp

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.

Clone this wiki locally