0% found this document useful (0 votes)
81 views11 pages

OpenGL Programming With Windows MFC

This document provides instructions for setting up an OpenGL view class with Microsoft's MFC framework in Visual Studio 2012. It describes how to create a new MFC application project, add necessary member functions to the generated COpenGLView class to handle window messages, link the OpenGL libraries, and run a basic test of the view class.

Uploaded by

igtdept
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
81 views11 pages

OpenGL Programming With Windows MFC

This document provides instructions for setting up an OpenGL view class with Microsoft's MFC framework in Visual Studio 2012. It describes how to create a new MFC application project, add necessary member functions to the generated COpenGLView class to handle window messages, link the OpenGL libraries, and run a basic test of the view class.

Uploaded by

igtdept
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 11

OpenGL Programming with Windows MFC

This exercise requires Visual Studio 2012 Professional Edition.

Before you begin this exercise, be sure you have installed freeGLUT and GLEW.

Building a Core Profile OpenGL View Class with MFC Framework


When Visual C++ has started, you will see a Start Screen similar to this one:

2. Create a New Project

The following show you how to create a framework for the OpenGL viewing class. You will need to perform the following steps.

Create a new project:


Select the "File" menu
Select "New | Project". A dialogue box will appear as shown below.
Under the project types section on the left, expand "Installed | Templates" and locate the "Visual C++" language templates. It might be under
"Other Languages" if you did not select C++ as your development environment when you first installed Visual Studio.
Select the MFC template category on the left, and choose "MFC Application" to the right.
In the "Name:" field, type OpenGL.
Leave the "Location:" field at the default. Note the path for future reference.
(*note, it is not recommended to work off of network drives; you may get strange messages and inconsistencies when you build your project
over a network).
Click the "OK" button.
You should now see a dialogue box as below:

You will notice that on the left hand side are seven project setting options. The three that you will modify are circled in red. For thoroughness, we
will go through all seven options.

In "Application Type"
Select "Single document"
Select "Document/View architecture support"
Un-select "Security Development Lifecycle (SDL) checks" - the security checks deprecate some insecure C routines that Dr. Angel's library
uses.
Un-select "Use Unicode libraries
Select "MFC standard" - this will adjust some settings for you.
Select "Use MFC in a shared DLL"
In "Compound Document Support"
Make sure "None" is selected
In "Document Template Properties"
You do not have to worry about any of these settings
In "Database Support"
Make sure "None" is selected
In "User Interface Features", the following setting are needed
"Thick frame"
"Minimize box"
"Maximize box"
Under "Command bars (menu/toolbar/ribbon):", select "Use a classic menu" and uncheck the toolbar options
You can ignore all other settings

In "Advanced Features"
Clear all the options (keep things simple for now)
In "Generated Classes"
Should see four: COpenGLView, COpenGLApp, COpenGLDoc, and CMainFrame
Click the "Finish" button

At this point, we have created a framework for the OpenGL program we are to develop. Your main window has changed. It now has three main regions.
Right Top: Code Editor where you can write and edit your programs. When you first start Visual Studio, this is the "Start Page".
Right Bottom: Feedback Area. Depending on your current activity this area might show code definitions, compiler output, or debug information.
Left: Project Management Panel: contains Solution Explorer (default), Class View, Property Manager, and Team Explorer. Choose the one you
want with tabs at the bottom.
Solution Explorer shows you the files in the project or solution that you are working on.
Class View enables you to see the class hierarchies in your project.
Property Manager can be ignored for now.
Team Explorer can be ignored for now.

If your window differs from the one pictured, you can still probably find the same elements. Most likely the Solution Explorer and Property manager will
be on the left. The exact layout does not matter much.

In the next section we will use the Class View tab in the Project Management Panel show the project's class hierarchy. There should be five classes
(CAboutDlg, CMainFrame, COpenGLApp, COpenGLDoc, and COpenGLView) automatically created for the OpenGL project. One of them, called
"COpenGLView", will be particularly interesting to you because the main task of this lab is to add message handling functions into this class to allow
OpenGL to set up and render the view at the appropriate times.

At this point, you might want to build and run the application (which of course does nothing yet) just to make sure your the wizard gave you a working
project.

It should look something like this:

3. Add Necessary Member Functions to the COpenGLView Class

The MFC Project Wizard creates the minimum number of member functions for each class being generated. We may take a look at them by looking at
the Class View:

Click on the "Class View" tab underneath the "Solution Explorer" on the right-hand side.
OR
Choose "View | Class View" from the menu

To examine COpenGLView class:

Expand the "OpenGL" project by clicking on the arrow to the left of "OpenGL".
You will now see the five classes that have been automatically created.
Click on "COpenGLView". There is no need to expand it.
If you examine the bottom panel of the Class view, you will see some member functions that have been automatically created including OnDraw
and PreCreateWindow.
Now, with COpenGLView selected, we can add functions for the following additional messages:

WM_CREATE (for OnCreate)


WM_DESTROY (for OnDestroy)
WM_SIZE (for OnSize)

To add functions for these messages, first ensure that you have selected "COpenGLView" in the "Class View", then press Alt + Enter to open the
Properties window. It will open on the right of the screen. You will notice that in the Properties window, some properties of "COpenGLView" are listed.
The icons along the top allow you to select other property types. We want to see and edit the message mapping list. Follow the example below to see
how this is done, then add message handler functions for all the messages listed above.

Click on the messages icon (circled in red in the diagram to the left)
You will see a listing of messages.

Scroll down in the "Messages" window

Click on message "WM_CREATE"


Notice that a drop-down arrow appears.

Click on the arrow and select " OnCreate".

You may notice that the OnCreate is added into the "Class View" window. Visual Studio has created
the member function for you. Remember that the system can only create a skeleton for the member
function. It is your responsibility to insert computations into the relevent member functions.

Click on COpenGLView again to add the next function and repeat as needed.

4. Compile Your Application

Choose "Build" from the menu options


Select "Build OpenGL"

It will take a little while to compile and link the program. You may look at the output from the compiling process being displayed in the Output region at
the bottom. If the project has compiled successfully, you will see a message like this:
---------------------- Done ----------------------
Build: 1 succeeded, 0 failed, 0 skipped

It is very exciting to run this little window's program if it is your first Windows program.
Choose "Debug" from the menu options
Select "Start Without Debugging"

A new window should be displayed in a few seconds. There are three menus: "File", "Edit", and "Help". These are the minimum options automatically
created by your VC++ system. Don't be surprised; the inside window is totally blank, because we haven't written any functions yet.

NOTE: On Alex Clarke's VS2012 Professional install the OnCreate has several lines of garbage code that did not appear in previous versions. If your
code does not compile try using this version of OnCreate instead:

int COpenGLView::OnCreate(LPCREATESTRUCT lpCreateStruct)


{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;

// TODO: Add your specialized creation code here

return 0;
}

5. Linking OpenGL Libraries

So far what we have created is all standard MFC stuff. It has nothing to do with OpenGL yet. To connect to OpenGL, we have do a few things first. Then
we may use functions from OpenGL library.

First, we need to insert the following lines into OpenGLView.h header file:

// Include the OpenGL headers


#include "Angel.h" //Dr. Angel's code does this for us

To add the above contents, you have to first find the desired header file. This is a good time to learn how to navigate around the files of the project.

Click the "Solution Explorer" tab (in the lower left), the "root" folder should be displayed.
Click the "+" node, and subfolders should be displayed. Two of them are of interest to you at the moment. They are "Source Files" and "Header
Files".
Click the "+" node to the left of the "Header Files" folder, you will see a number of header files are listed. One of them is "OpenGLView.h"
Double click on this filename. The contents of the "Editing Window" change to the contents in this file.

Now, you may add the above contents at the very beginning of this header file. Remember to save the document before you close this Editing window.

The next step is to add the OpenGL libraries to the link line:

Choose the "Project" menu option


Select "OpenGL Properties"
A dialogue box will appear similar to below.
Click on the "Linker" folder to the left side of the dialogue
In the sub sections of "Linker", click "Input".
You should now see "Additional Dependencies" on the top right-hand side.
Select the "Additional Dependencies", click the arrow that appears to the right and select ""
att the following content to the top box:
opengl32.lib;glu32.lib;freeglut.lib;glew32.lib
Click "OK", then "OK" again.

Last, but not least, add support code from Lab 1 to your project by:
Downloading Angel.zip, uofrGraphics.zip
Extracting the files into your project folder next to the .cpp files that were generated by the Visual Studio wizard.
Downloading the shaders vshader.glsl and fshader.glsl to the project folder.
Adding all the new files (Angel.h, CheckErrors.h, fshader.glsl, InitShaders.cpp, mat.h, uofrGraphics.cpp uofrGraphics.h, vec.h,
and vshader.glsli) to your project with the "Project | Add Existing Item..." menu item.
Adding the line #include "stdafx.h" as the very first line in InitShader.cpp and uofrGraphics.h
Adding the line #include <wglew.h> immediately after the line #include <glew.h>.

At this point, you might want compile your application again to make sure that everything is right so far.

D. Editing Member Functions


Now that the OpenGL libraries have been added to our project, we are ready add some real OpenGL code. For this lab, you are concerned with the
COpenGLView class only. Therefore, you will work with two files:

OpenGLView.h
OpenGLView.cpp

The code you will add will:

1. Create and set up a Device Context


2. Establish a Rendering Context
3. Handle window events
4. Draw a scene
5. Clean up after itself

For now here are the changes you need to make to the two files. The parts you will work with are highlighted in red.

File: OpenGLView.h
// OpenGLView.h : interface of the COpenGLView class

// You should have already added this line.


#include "Angel.h"

......

class COpenGLView : public CView


{
protected: // create from serialization only
.....

// Attributes
public:
......

// Operations
public:

// Overrides
public:
......

// Implementation
public:
......

protected:
// You will add the following stuff!!!

virtual BOOL GetOldStyleRenderingContext( void );


virtual BOOL SetupPixelFormat( void );

private:
//OpenGL Setup
BOOL GetRenderingContext();
//Rendering Context and Device Context Pointers
HGLRC m_hRC;
CDC* m_pDC;

//Error Handling
void SetError( int e );
static const char* const _ErrorStrings[];
const char* m_ErrorString;

// Generated message map functions


protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg void OnSize(UINT nType, int cx, int cy);
};

......

OpenGLView.cpp
// OpenGLView.cpp : implementation of the COpenGLView class

#include "stdafx.h"

// SHARED_HANDLERS can be defined in an ATL project implementing preview, thumbnail


// and search filter handlers and allows sharing of document code with that project.
#ifndef SHARED_HANDLERS
#include "OpenGL.h"
#endif

#include "OpenGLDoc.h"
#include "OpenGLView.h"

// Add code from Prototypes and Global Variables Section


// of lab 1 notes

......

// COpenGLView

IMPLEMENT_DYNCREATE(COpenGLView, CView)

BEGIN_MESSAGE_MAP(COpenGLView, CView)
......
END_MESSAGE_MAP()

// You will add stuff here!!!!


const char* const COpenGLView::_ErrorStrings[]= {
{"No Error"}, // 0
{"Unable to get a DC"}, // 1
{"ChoosePixelFormat failed"}, // 2
{"SelectPixelFormat failed"}, // 3
{"wglCreateContext failed"}, // 4
{"wglMakeCurrent failed"}, // 5
{"wglDeleteContext failed"}, // 6
{"SwapBuffers failed"}, // 7
};

// COpenGLView construction/destruction

COpenGLView::COpenGLView()
// You will add the following line !!!
: m_hRC(0), m_pDC(0), m_ErrorString(_ErrorStrings[0]) // Call constructors

{
......
}

......

BOOL COpenGLView::PreCreateWindow(CREATESTRUCT& cs)


{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs

// You will add stuff here !!!


// An OpenGL window must be created with the following flags and must not
// include CS_PARENTDC for the class style.
cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

return CView::PreCreateWindow(cs);
}

// COpenGLView drawing

void COpenGLView::OnDraw(CDC* pDC)


{
COpenGLDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
// Find the OpenGL drawing function provided in the Lab 1 notes and call it here

//Swap buffers to show result


if ( FALSE == ::SwapBuffers( m_pDC->GetSafeHdc() ) )
{
SetError(7);
}
}

......

// COpenGLView message handlers

int COpenGLView::OnCreate(LPCREATESTRUCT lpCreateStruct)


{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;

// TODO: Add your specialized creation code here


GetRenderingContext();
if (!GetRenderingContext())
{
//Something went wrong with getting the rendering context.
//Create a popup with the error message, then quit.
AfxMessageBox(CString(m_ErrorString));
return -1;
}

// We now have a rendering context, so we can set the initial drawing state.
// Find the initialize OpenGL function provided in the Lab 1 notes and call it here

return 0;
}

void COpenGLView::OnDestroy()
{
CView::OnDestroy();

// TODO: Add your message handler code here


if ( FALSE == ::wglDeleteContext( m_hRC ) )
{
SetError(6);
}

if ( m_pDC )
{
delete m_pDC;
}

void COpenGLView::OnSize(UINT nType, int cx, int cy)


{
CView::OnSize(nType, cx, cy);

// TODO: Add your message handler code here


// A resize event occured; cx and cy are the window's new width and height.
// Find the OpenGL change size function given in the Lab 1 notes and call it here

/////////////////////////////////////////////////////////////////////////////
// GL Rendering Context Creation Functions
//
// Since we are using Windows native windowing, we need to set up our own
// OpenGL rendering context. These functions do it to the main view area.
// It is possible to do it to a smaller sub view. If you are curious, you can
// find tutorials on how to do that on the net.
//

// Error reporting utility


void COpenGLView::SetError( int e )
{
// if there was no previous error,
// then save this one
if ( _ErrorStrings[0] == m_ErrorString )
{
m_ErrorString = _ErrorStrings[e];
}
}

BOOL COpenGLView::GetRenderingContext()
{
// Can we put this in the constructor?
m_pDC = new CClientDC(this);

if ( NULL == m_pDC ) // failure to get DC


{
SetError(1);
return FALSE;
}

if (!GetOldStyleRenderingContext())
{
return TRUE;
}

//Get access to modern OpenGL functionality from this old style context.
glewExperimental = GL_TRUE;
if (GLEW_OK != glewInit())
{
AfxMessageBox(_T("GLEW could not be initialized!"));
return FALSE;
}

//Get a new style pixel format


if (!SetupPixelFormat())
{
return FALSE;
}

//Setup request for OpenGL 3.2 Core Profile


int attribs[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
//WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
0, 0 //End
};

if(wglewIsSupported("WGL_ARB_create_context") == 1)
{
//If this driver supports new style rendering contexts, create one
HGLRC oldContext = m_hRC;
if ( 0 == (m_hRC = m_hRC = wglCreateContextAttribsARB(m_pDC->GetSafeHdc(),0, attribs) ) )
{
SetError(4);
return FALSE;
}

if(!wglMakeCurrent(NULL,NULL) )
wglDeleteContext(oldContext);
if ( FALSE == wglMakeCurrent( m_pDC->GetSafeHdc(), m_hRC ) )
{
SetError(5);
return FALSE;
}
}
else
{
//Otherwise use the old style rendering context we created earlier.
AfxMessageBox(_T("GL 3.2 Context not possible. Using old style context. (GL 2.1 and before)"));
}

return TRUE;
}

BOOL COpenGLView::GetOldStyleRenderingContext()
{
//A generic pixel format descriptor. This will be replaced with a more
//specific and modern one later, so don't worry about it too much.
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
32, // 32-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
24, // 24-bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};

// Get the id number for the best match supported by the hardware device context
// to what is described in pfd
int pixelFormat = ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd);

//If there's no match, report an error


if ( 0 == pixelFormat )
{
SetError(2);
return FALSE;
}

//If there is an acceptable match, set it as the current


if ( FALSE == SetPixelFormat(m_pDC->GetSafeHdc(), pixelFormat, &pfd) )
{
SetError(3);
return FALSE;
}

//Create a context with this pixel format


if ( 0 == (m_hRC = wglCreateContext( m_pDC->GetSafeHdc() ) ) )
{
SetError(4);
return FALSE;
}

//Make it current. Now we're ready to get extended features.


if ( FALSE == wglMakeCurrent( m_pDC->GetSafeHdc(), m_hRC ) )
{
SetError(5);
return FALSE;
}
return TRUE;
}

BOOL COpenGLView::SetupPixelFormat()
{
//This is a modern pixel format attribute list.
//It has an extensible structure. Just add in more argument pairs
//befroe the null to request more features.
const int attribList[] =
{
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0, 0 //End
};

unsigned int numFormats;


int pixelFormat;
PIXELFORMATDESCRIPTOR pfd;

//Select a pixel format number


wglChoosePixelFormatARB(m_pDC->GetSafeHdc(), attribList, NULL, 1, &pixelFormat, &numFormats);

//Optional: Get the pixel format's description. We must provide a


//description to SetPixelFormat(), but its contents mean little.
//According to MSDN:
// The system's metafile component uses this structure to record the logical
// pixel format specification. The structure has no other effect upon the
// behavior of the SetPixelFormat function.
//DescribePixelFormat(m_pDC->GetSafeHdc(), pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

//Set it as the current


if ( FALSE == SetPixelFormat(m_pDC->GetSafeHdc(), pixelFormat, &pfd) )
{
SetError(3);
return FALSE;
}

return TRUE;
}

// Add the definitions for the OpenGL initialize, resize, and draw functions from the lab notes!

Once you have modified the above two files, you can compile and run the program.

If you got errors, you might have forgotten to add the OpenGL code from the lab notes to the OpenGLView.h and OpenGLView.cpp! You will also need
the correct shaders, or the program will appear not to start. If you get a warning that says "GL 3.2 Context not possible", you have a graphics card that
doesn't support OpenGL 3.2 Core Profile and you will have to either update your drivers, or try again with a newer card. I suggest any nVidia or AMD
card produced in the last couple years.

E. Clean Your Project Before You Submit It


To clean up your project for submission delete all Debug folders in the project and delete all sdf files. They are rather large (in some cases > 30 MB)
and the .exe file in the Debug folder will be rejected by many spam filtering systems. Besides, you will get them back the next time you compile your
program.

You might also like