Compiling OpenGL Code with MFC
This article is little more than code, but it should at least give you a framework for using OpenGL in MFC applications.
PRO Tired of ads? Read GameDev.net ad-free and help keep the community independent with GameDev Pro — $3/month.
[size="3"]MainFrame Class
Step 1: In the Mainframe Class override the initial dimensions of the default Window. Using the CREATESTRUCT we change the dimensions of the window to 400 x 400
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.cx=400;
cs.cy=400;
return CFrameWnd::PreCreateWindow(cs);
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.cx=400;
cs.cy=400;
return CFrameWnd::PreCreateWindow(cs);
}
BOOL CMainFrame::OnQueryNewPalette()
{
// TODO: Add your message handler code here and/or call default
CView *pView=GetActiveView();
pView->Invalidate(FALSE);
return CFrameWnd::OnQueryNewPalette();
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.cx=400;
cs.cy=400;
return CFrameWnd::PreCreateWindow(cs);
}Step 1: Step up the pixel format and create a rendering context
int CMfc_cubeView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
PIXELFORMATDESCRIPTOR pfd=
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW|
PFD_SUPPORT_OPENGL|
PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
24, //24-bit color
0,0,0,0,0,0,
0,0,0,0,0,0,0,
32, //32 bit depth buffer
0,0,
PFD_MAIN_PLANE, //Main layer type
0,
0,0,0
};
CClientDC clientDC(this);
/*
ChoosePixelFormat
Requests a pixel-format index for a pixel format that most closely
matches the format requested. This function's two arguments are a
handle to the DC for which to select the pixel format and the
address of the PIXELFORMATDESCRIPTOR structure that holds the attributes
of the requested pixel format
*/
int pixelFormat =ChoosePixelFormat(clientDC.m_hDC,&pfd);
BOOL success = SetPixelFormat(clientDC.m_hDC,pixelFormat,&pfd);
/*
DescribePixelFormat
Fills a PIXELFORMATDESCRIPTOR structure with information about the given
pixel format. This function's four arguments are a handle to the DC, the
pixel index to examine, and the size and address of PIXELFORMATDESCRIPTOR structure.
*/
DescribePixelFormat(clientDC.m_hDC,pixelFormat, sizeof(pfd),&pfd);
if (pfd.dwFlags & PFD_NEED_PALETTE)
SetupLogicalPalette();
/*
wglCreateContext
Creates a rendering context compatible with the given DC.
*/
m_hRC=wglCreateContext(clientDC.m_hDC);
/*
wglMakeCurrent
Makes a rendering context current, which binds the rendering
context to the given DC. This function's two arguments
are a handle to a DC and the handle to the rendering context.
*/
wglMakeCurrent(clientDC.m_hDC,m_hRC);
//Texture Mapping
//Once you have your DIB loaded and its color tables created, you can
// actually start thinking about your texture mapping
//GL_TEXTURE_2D equates to a two-dimensional texture
//GL_CLAMP for a single image
//GL_REPEAT for a repeating pattern
//GL_TEXTURE_MAG_FILTER determines how a texture is magnified when
// the destination is larger than the texture.
//GL_TEXTURE_MIN_FILTER determines how a texture is reduced
//glTexEnvi set the texturing environment
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
glEnable(GL_DEPTH);
glEnable(GL_TEXTURE_2D);
glClearColor(1.0f,1.0f,1.0f,1.0f);
wglMakeCurrent(clientDC.m_hDC,NULL);
/* CDib is a class used to read Device Independant Bitmaps */
m_pDib = new CDib("snake.BMP");
CreateColorTables(m_pDib);
SetupColorTables();
/* The timer determines the rendering refresh rate in milliseconds*/
SetTimer(1,1,0);
return 0;
}void CMfc_cubeView::OnDestroy()
{
CView::OnDestroy();
// TODO: Add your message handler code here
KillTimer(1);
delete m_pDib;
/*Frees the Rendering Context. Cleanup of resources*/
wglDeleteContext(m_hRC);
if (m_hPalette)
DeleteObject(m_hPalette);
}BOOL CMfc_cubeView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
return CView::PreCreateWindow(cs);
}void CMfc_cubeView::OnDraw(CDC* pDC)
{
CMfc_cubeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
if (m_hPalette)
{
SelectPalette(pDC->m_hDC,m_hPalette, FALSE);
RealizePalette(pDC->m_hDC);
}
wglMakeCurrent(pDC->m_hDC,m_hRC);
DrawWithOpenGL();
SwapBuffers(pDC->m_hDC);
wglMakeCurrent(pDC->m_hDC,NULL);
}void CMfc_cubeView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
CClientDC clientDC(this);
wglMakeCurrent(clientDC.m_hDC,m_hRC);
glViewport(0,0,cx,cy);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0,1.0,-1.0,1.0,2.0,9.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLfloat light0Ambient[]={0.0f,0.0f,0.0f,1.0f};
GLfloat light0Diffuse[]={1.0f,1.0f,1.0f,1.0f};
GLfloat light0Position[]={0.0f,0.0f,0.0f,1.0f};
glLightfv(GL_LIGHT0,GL_AMBIENT,light0Ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE, light0Diffuse);
glLightfv(GL_LIGHT0,GL_POSITION,light0Position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glTranslatef(0.0f,0.0f,-6.0f);
wglMakeCurrent(NULL,NULL);
}void CMfc_cubeView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
if (m_cube_animate==1 )
{
m_cube_spin+=2;
}
if (m_icosa_animate==1)
{
m_icosa_spin+=2;
}
Invalidate(FALSE);
CView::OnTimer(nIDEvent);
}void CMfc_cubeView::DrawWithOpenGL()
{
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
AnimateCube();
}void CMfc_cubeView::AnimateCube()
{
GLfloat glfMaterialColor[]={0.2f,0.8f,0.5f,1.0f};
GLvoid* pTextureBits = (GLvoid*) m_pDib->GetDibBitsPtr();
GLint width = m_pDib->GetDibWidth();
GLint height = m_pDib->GetDibHeight();
glPushMatrix();
glTexImage2D(GL_TEXTURE_2D,0,3,width,height,0,GL_COLOR_INDEX,
GL_UNSIGNED_BYTE,pTextureBits);
glClear(GL_COLOR_INDEX|GL_DEPTH_BUFFER_BIT);
glRotatef(m_cube_spin,1.0,1.0,1.0);
glScalef (0.5,0.5,0.5); /* modeling transformation */
//glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,glfMaterialColor);
glBegin(GL_POLYGON);
//glNormal3f(0.0f,0.0f,1.0f);
//vertice 1
glTexCoord2f(0.0f,1.0f);
glVertex3f(1.0f,1.0f,1.0f);
//vertice 2
glTexCoord2f(0.0f,0.0f);
glVertex3f(-1.0f,1.0f,1.0f);
//vertice 3
glTexCoord2f(1.0f,0.0f);
glVertex3f(-1.0f,-1.0f,1.0f);
//vertice 4
glTexCoord2f(1.0f,1.0f);
glVertex3f(1.0f,-1.0f,1.0f);
glEnd();
glBegin(GL_POLYGON);
//glNormal3f(0.0f,0.0f,-1.0f);
//vertice 1
glTexCoord2f(0.0f,1.0f);
glVertex3f(1.0f,1.0f,-1.0f);
//vertice 2
glTexCoord2f(0.0f,0.0f);
glVertex3f(1.0f,-1.0f,-1.0f);
//vertice 3
glTexCoord2f(1.0f,0.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
//vertice 4
glTexCoord2f(0.0f,0.0f);
glVertex3f(-1.0f,1.0f,-1.0f);
glEnd();
glBegin(GL_POLYGON);
//glNormal3f(-1.0f,0.0f,0.0f);
//vertice 1
glTexCoord2f(0.0f,1.0f);
glVertex3f(-1.0f,1.0f,1.0f);
//vertice 2
glTexCoord2f(0.0f,0.0f);
glVertex3f(-1.0f,1.0f,-1.0f);
//vertice 3
glTexCoord2f(1.0f,0.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
//vertice 4
glTexCoord2f(1.0f,1.0f);
glVertex3f(-1.0f,-1.0f,1.0f);
glEnd();
glBegin(GL_POLYGON);
//glNormal3f(1.0f,0.0f,0.0f);
//vertice 1
glTexCoord2f(0.0f,1.0f);
glVertex3f(1.0f,1.0f,1.0f);
//vertice 2
glTexCoord2f(0.0f,0.0f);
glVertex3f(1.0f,-1.0f,1.0f);
//vertice 3
glTexCoord2f(1.0f,0.0f);
glVertex3f(1.0f,-1.0f,-1.0f);
//vertice 4
glTexCoord2f(1.0f,1.0f);
glVertex3f(1.0f,1.0f,-1.0f);
glEnd();
glBegin(GL_POLYGON);
//glNormal3f(0.0f,1.0f,0.0f);
//vertice 1
glTexCoord2f(0.0f,1.0f);
glVertex3f(-1.0f,1.0f,-1.0f);
//vertice 2
glTexCoord2f(0.0f,0.0f);
glVertex3f(-1.0f,1.0f,1.0f);
//vertice 3
glTexCoord2f(1.0f,0.0f);
glVertex3f(1.0f,1.0f,1.0f);
//vertice 4
glTexCoord2f(1.0f,1.0f);
glVertex3f(1.0f,1.0f,-1.0f);
glEnd();
glBegin(GL_POLYGON);
//glNormal3f(0.0f,-1.0f,0.0f);
//vertice 1
glTexCoord2f(0.0f,1.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
//vertice 2
glTexCoord2f(0.0f,0.0f);
glVertex3f(1.0f,-1.0f,-1.0f);
//vertice 3
glTexCoord2f(1.0f,0.0f);
glVertex3f(1.0f,-1.0f,1.0f);
//vertice 4
glTexCoord2f(1.0f,1.0f);
glVertex3f(-1.0f,-1.0f,1.0f);
glEnd();
glPopMatrix();
}
void CMfc_cubeView::CreateColorTables(CDib *pDib)
{
LPRGBQUAD pColorTable = pDib->GetDibRGBTablePtr();
for(UINT i=0; i<256; ++i)
{
m_red=(GLfloat) pColorTable.rgbRed/255;
m_green=(GLfloat) pColorTable.rgbGreen/255;
m_blue=(GLfloat) pColorTable.rgbBlue/255;
}
}
void CMfc_cubeView::SetupColorTables()
{
CClientDC clientDC(this);
wglMakeCurrent(clientDC.m_hDC,m_hRC);
glPixelMapfv(GL_PIXEL_MAP_I_TO_R,256,m_red);
glPixelMapfv(GL_PIXEL_MAP_I_TO_G,256,m_green);
glPixelMapfv(GL_PIXEL_MAP_I_TO_B,256,m_blue);
glPixelTransferi(GL_MAP_COLOR,TRUE);
wglMakeCurrent(clientDC.m_hDC,m_hRC);
}
void CMfc_cubeView::SetupLogicalPalette()
{
struct
{
WORD Version;
WORD NumberOfEntries;
PALETTEENTRY aEntries[256];
}logicalPalette={0x300,256};
BYTE reds[]={0,36,72,109,145,182,218,255};
BYTE greens[]={0,36,72,109,145,182,218,255};
BYTE blues[]={0,85,170,255};
for(int colorNum=0; colorNum<256; ++colorNum)
{
logicalPalette.aEntries[colorNum].peRed=reds[colorNum&0x07];
logicalPalette.aEntries[colorNum].peGreen=greens[(colorNum>>0x03)&0x07];
logicalPalette.aEntries[colorNum].peBlue=blues[(colorNum>>0x06)&0x03];
logicalPalette.aEntries[colorNum].peFlags=0;
}
m_hPalette=CreatePalette ((LOGPALETTE*)&logicalPalette);
}Related Tutorials
Procedural Generation of 2D Tile Maps in Games
The article explains how to build a procedural 2D cave map generator using cellular automata. It covers map representat…
Localizing A Game Into French — Which Variant Should You Choose?
So, you’re making an awesome indie game, and now you’re thinking about localizing it into French? Great idea! There ar…
How Long Does It Take To Localize An Indie Game?
So you’re planning on localizing your indie game, but you’re not sure how much time to schedule in. While the timing o…
Creating game videos: best practices and pitfalls to avoid
Game video production: practical tips on how to create a game trailer or teaser that you can be proud of. Give your aud…
Adopting CI/CD: How Midwinter Entertainment iterates at speed with the help of IMS
Game development was once like one long sprint: a huge effort until you reached the finish line — at which point you co…
GameDev.net
5 Things to Consider When Making a Video to Promote Your App or Game
How can you show an app or game in your video in a way that attracts new users? Let’s take a look at what to go by when…
Discussion
More from David Nishimoto
Comparing Shadow Mapping Techniques with Shadow Explorer
New Incentives and a Whole New Platform From The Intel AppUp developer program
The final installment in this series on Intel's AppUp program details additional incentives and opportunities for devel…
The Game Maker
This book excerpt contains the first chapter of the book that introduces beginning game developers to the Game Maker pr…
Discussion