Tutorial One - Skeleton Project

 Download the WocSkeleton EXE (74KB) in compressed ZIP format.

 Download the WocSkeleton project files (6KB) in compressed ZIP format.

For this and all the tutorials you will need to download the WOC header and implementation files. I recommend that you unzip them into a folder named woc and locate it at the same level as (i.e. a sibling of) the project folders which use it. This is because the projects look for the WOC files at the path: ..\woc\ as we'll see later.


WinZip® brings the convenience of Windows to the use of Zip files and other compression formats. If you don't have "the most celebrated shareware app in the history of computing" already, use the above link to download it.
   
About the tutorial
If you like WOC and find it useful then you may want to use it more than once - perhaps even lots of times. In that case it's nice to have a skeleton or template project to model new WOC projects on. That's where WOCSkeleton comes in. This tutorial shows you how to integrate the WOC source files into a Visual C++ project, but you can then save the project and re-use it as a starting-point for new projects. You can either follow along with the steps or just download the project source code. Of course you don't have to use a skeleton project if you don't want to, but you'll find it more convenient than following these steps each time you make a new project.
 
   
The steps
1. Launch Visual C++® and use the Win32 Application wizard to create a new project named WocSkeleton. Locate the project folder as a sibling of the woc folder containing the WOC header and implementation files. The steps which follow apply to the 'Hello World' option (on Step 1 of the Win32 Application Wizard), but feel free to choose one of the others if you're happy to add the appropriate files, code and resources on your own to make a minimal Win32 application.

2. Open the file stdafx.h for editing. There is usually a comment near the end of the file indicating where to place your own headers:
// TODO: reference additional headers your program requires here
Even if you don't have this comment, just find a suitable place near the end of the file before the close of the include guard and paste this:
#include "woc.h"	// directory path set in project settings.
using namespace woc;
This is an include of the main WOC header file which in turn includes several other WOC header files. Together these files contain the definitions of all of WOC's types, and some complete implementations. Because stdafx.h is included by the other source files in the project, all names in the woc namespace will now be defined throughout the project. At this stage the project doesn't yet know where to find the file - that's done in step 3. However, you can opt to hard-code the path to the file here (even a relative path) and skip step 3. It's up to you.

3. If a project includes a lot of header files from the same folder, and the name or location of that folder may change, then you wouldn't want to have to edit the path in every #include. Although WOC's include structure presently obviates the explicit including of more than one header file, that may not always be the case. So, if you followed step 2 to the letter then now you'll need to let the project know where to look for additional header files, specifically woc.h. You could make this setting for the whole of Visual Studio by adding a new include file directory on the Directories tab of the Options dialog (Tools/Options... menu), but I prefer to make the setting apply only to the project at hand so that it will easily transfer between Visual Studio installations. To do this, choose Project/Settings..., choose Settings For: All Configurations, choose the C/C++ tab, Category: Preprocessor, and in the Additional include directories: edit box, paste:

..\woc\

This is correct for the case where the woc folder is a sibling of the new project's folder. You may choose a different arrangement but, if you do, then you should edit the above include directory path to match. Note that the Additional include directories: edit box may contain more than one path, comma-separated. There is one more change to make whilst you're editing the project settings. Use of the dynamic_cast operator requires run-time type information which is enabled with the /GR compiler switch. So, choose Settings For: All Configurations, the C/C++ tab, Category: C++ Language, and check the Enable Run-Time Type Information (RTTI) checkbox.

4. The project will now compile, but so that it will also link when we come to using the WOC classes, you'll need to add the implementation file to the project's Source Files folder on the FileView tab of the Workspace pane. Right-click the Source Files folder, choose Add Files to Folder... from the context menu, navigate to the woc folder and choose the file woc.cpp. Whilst you're at the FileView tab you can also add all the WOC header files (woc.h and all the others you'll find in the folder) to the Header Files folder so that all the WOC classes will appear on the ClassView tab.

5. One final step before the project will link is to reference the static library files for OpenGL and the Win32 Common Controls. To do this, choose Project/Settings..., choose Settings For: All Configurations, choose the Link tab, Category: General, and in the Object/library modules: edit box, add:

opengl32.lib glu32.lib glaux.lib comctl32.lib

Now the project will build. Just check that it does.

6. At present the project is using no WOC features and, if you run it, it will behave as it did when it was first generated by the wizard. Now we need to remove most of the wizard-generated Windows code and replace it with a small amout of WOC code. Open the file WocSkeleton.cpp for editing and delete everything from it except the #include directives and the WinMain function. Next, delete all the code from the body of the WinMain function and paste this in its place:
// Perform application initialization:
if (!theApp.InitInstance(hInstance,
                         nCmdShow,
                         IDC_WOCSKELETON,
                         IDI_WOCSKELETON,
                         IDI_SMALL,
                         NULL,
                         IDS_APP_TITLE)) 
{
	return FALSE;
}
return theApp.MessageLoop((LPCTSTR)IDC_WOCSKELETON);
You may be wondering about the identifier theApp - where is it declared? Nowhere as yet, so add the following declaration after the includes but before WinMain:
// The one and only application object.
CWocApp < CWocFrameWnd < CWocOGLWnd > > theApp;
The meaning of this code is that we are declaring an identifier named theApp which is of type CWocApp. This is a class template whose single template parameter specifies the type of window to use for the application's main window (defaults to CWocFrameWnd ). The parameter can be any CWocWnd-derived class so long as it implements a CreateFrame method as CWocFrameWnd and CWocOGLWnd do. The CWocFrameWnd class is another class template whose single parameter specifies the type of the view window it may be required to use to overlay the client area of the frame window. The parameter must either be CWocWnd (the default) or a class derived from it. Incidentally, the constructor of the frame window object takes a BOOL parameter, defaulting to TRUE, indicating whether or not the frame window is required to create a view. If this parameter is FALSE then the view type is ignored. If we wanted to override the default of creating a view then we have to wait until the application object has created the frame window then call SetCreateView(FALSE) on the frame window at any time, but most logically in an overriden OnCreate handler.

7. Now you can build and run the sample, so let's leave further code editing until the next step whilst we look at some of the default features of the classes. The code that earlier I directed you to insert specifies the view of the main frame window to be an OpenGL rendering context window (CWocOGLWnd). When you run the sample you'll see the default behaviour of the CWocOGLWnd class. Firstly, a default 3-D model is displayed which is lit and rotating and its normals are shown. How this happens is that an (overridable) initialiser function in the OpenGL window class (the member is CWocOGLWnd::InitialiseGL if you want to take a look at it) creates a new model object, loads some geometry and face normals into it and then calls a method on the model to require it to show its normals. The model then makes some changes to the OpenGL state to reflect its requirements and, since normals now exist, the model requests the view class to activate lighting and GL_LIGHT0. The view class also defaults to rotating the scene a small amount on a timer which fires every few milliseconds. The CWocOGLWnd class has two significant features: a mouse interface to manipulate the view transformations, and a Properties Dialog.

Mouse manipulation is a mode which you can toggle into and out of by holding down Ctrl and right-mouse clicking inside the view. When you're in mouse manipulating mode the mouse cursor will disappear and you can manipulate the scene in several ways, even whilst model animation is taking place, by moving the mouse with various combinations of the mouse buttons depressed. With no buttons depressed the view is rotated about the X and Y axes; the left button causes rotation about the Z axis; the right button causes zooming in and out; and both mouse buttons depressed together causes the view to pan.

Getting the OpenGL Window Properties Dialog to display can be done either programmatically by calling CWocOGLWnd::PropertiesDialogDoModeless or by the user double-clicking the right mouse button anywhere inside an OpenGL Window. For a full explanation of all the controls on the OpenGL Window Properties Dialog together with the theory behind them, please see the documentation for the CWocOGLWndPropertiesDialog class (nested within the CWocOGLWnd class) in the WOC Class Reference.

8. Now to reactivate the application's main menu. The project wizard created an About dialog box resource along with a dialog procedure and command handler to display the dialog. Earlier we deleted that code but we still have the dialog resource and, as you'll see, it's very easy to add a handler to your project to handle the menu commands and to create and display the dialog. First, in order to control the handling of specific commands, we need to override the command handling functionality in the default frame window class CWocFrameWnd. Command handlers exist in all of WOC's window classes: standard windows, frame windows and consequently any window used as a view. This means that you can either derive your own frame window and add a command handler to it or do the same with a view window; the only difference being that frame windows get to handle commands before their views. In this case, because the purposes of the menu commands being handled are 1. to close the application and 2. to display the application's About box, the most appropriate place to handle these commands is in the application's main frame window. The plan then is to derive a class from the existing CWocFrameWnd template class and implement the virtual OnCommand method on the derived class. Paste the following code into WocSkeleton.cpp immediately before your declaration of theApp:
template < class _TyView = CWocOGLWnd > class CWocSkeletonFrameWnd : 
    public CWocFrameWnd < _TyView > 
{ 
public: 
    CWocSkeletonFrameWnd(BOOL nCreateView = TRUE) : 
        CWocFrameWnd < _TyView >(nCreateView){}; 
    virtual ~CWocSkeletonFrameWnd(){}; 

    virtual BOOL OnMenuOrAcceleratorCommand (UINT nId) 
    { 
        switch (nId) 
        { 
            case IDM_EXIT : 
                return theApp.Exit(); 
            case IDM_ABOUT : 
            { 
                CWocDialog dlgAbout(IDD_ABOUTBOX, this);
                dlgAbout.DoModal(); 
                break; 
            } 
            default: 
                return CWocFrameWnd < _TyView >::OnMenuOrAcceleratorCommand(nId);
        } 
        return 0;	// indicate that the message has been handled. 
    } 
}; 
So what are the handlers doing? The IDM_EXIT handler is simply calling a method on your application object to destroy the main window and thus quit the application. The IDM_ABOUT handler makes use of the CWocDialog class which in this case needs no specialisation as it handles IDOK and IDCANCEL straight out of the box. The arguments passed to the constructor of CWocDialog are: the dialog's template resource ID, and a pointer to the window object which owns the dialog. Finally, we have to amend the type of our application object as its main window is no longer the base frame window class but rather the class we've just defined. So replace your theApp declaration with this line:

CWocApp < CWocSkeletonFrameWnd < > > theApp;

And that's it! If you build and run now you'll find that your menu works again. I'll be referring to the WocSkeleton project in the following tutorials as they will all use it as a starting point. For this reason I suggest you save your project and put it aside if you've been following along, or just download the WOCSkeleton project files if you prefer.
 
last updated: 10-oct-01