Using OpenGL with MFC

导读:
  This tutorial is intended to describe how to setup MFC with OpenGL or how to setup OpenGL with MFC.
  In this lesson we'll create a simple MFC project, workspace and application. The project will create a window complete with menu, toolbar, status bar and rotate a nice torus in the window.
   Introduction
  First off, Download the codefor this lesson.
  This tutorial is intended to describe how to setup MFC with OpenGL or how to setup OpenGL with MFC, depending on your point of view. Many people have asked for this and it's a topic that comes up frequently on the message boards so here it is. It's also surprisingly simple to do.
  MFC really is easy to use once you get used to it and Visual C++ IDE does a tremendous job of automating the development process. So let's get started.
  In this lesson we'll create a simple MFC project, workspace and application. The project will create a window complete with menu, toolbar, status bar and rotate a nice torus in the window.
  
  
  First thing you want to do is create the project. Fire up VC++ and create a new MFC App Wizard project. Move through the wizard, entering the parameters as you see fit. It really doesn't matter what you pick here so go nuts.
  Here's a shot of the classes you'll end up with.
  VC generates lots of neat code for you. It's a good idea to have it insert "TODO" comments as this will help you figure out what most of the methods are for.
  Now let's prepare the window. First off you need to modify the window in the PreCreateWindow method of the View class so that the window can work with OpenGL. Do this by adding the following lines to your project:
  BOOL CMfc_basicView::PreCreateWindow(CREATESTRUCT& cs)
  {
  // Add Window styles required for OpenGL before window is created
  cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CS_OWNDC);
  return CView::PreCreateWindow(cs);
  }
  
  
  Make your PreCreateWindow look like mine ( with the exception of the CMFC_basicView:: piece, this is the class name and will differ based on what you named your project/class ).
  Ok, let's get the include files inserted into the project. But where do they go I hear you ask: Since we'll be using openGL calls from potentially anywhere in the application, we'll add them to a file called stdafx.h. You may need to go find this file under the "headers" section in the File view of the Workspace window.
  Here's a snippet from that file that includes the last line generated by VC++ and the include files I've added.
  #include
  // MFC support for Windows Common Controls
  // Inserted these files for openGL
  #include
  #include
  #include
  #include
  #endif // _AFX_NO_AFXCMN_SUPPORT
  Now we'll setup the PixelFormat etc. for OpenGL. Before we do, here are a couple of member variables I find it useful to add to the View class at this point. They are the following.
  Just paste these into your View class .h file under Attributes, public section.
  HGLRC m_hRC; // Permanent Rendering Context
  HDC m_myhDC; // Private GDI Device Context
  int m_height; // Stores the height of the View
  int m_width; // Stores the width of the view
  These variables store the rendering and Device context information.
  I also like to store the width and height in case I need them. I could use a GetRect call to obtain these when I need them but I like to grab'em and store them when the window is re-sized. We'll see that later.
  While you're in the View class header add the following method : BOOL SetupPixelFormat();
  You can use VC++'s tool to do this by right-clicking on the View class and then selecting Add Member Function. I recommend using this method as it's going to generate the .h statement and the body of the function for you. Here's the code I enter into that method. It's pretty much the same as every other OpenGL function and I've commented the code so it should make sense. Let me know if you need any further explanation.
  BOOL COglm_demoView::SetupPixelFormat()
  {
  GLuint PixelFormat;
  static PIXELFORMATDESCRIPTOR pfd= {
  sizeof(PIXELFORMATDESCRIPTOR),
  // Size Of This Pixel Format Descriptor
  1,
  // Version Number (?)
  PFD_DRAW_TO_WINDOW | // Format Must Support Window
  PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
  PFD_DOUBLEBUFFER, // Must Support Double Buffering
  PFD_TYPE_RGBA, // Request An RGBA Format
  24, // Select A 24Bit 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, // Accumulation Bits Ignored (?)
  16, // 16Bit Z-Buffer (Depth Buffer)
  0, // No Stencil Buffer
  0, // No Auxiliary Buffer (?)
  PFD_MAIN_PLANE, // Main Drawing Layer
  0, // Reserved (?)
  0, 0, 0 // Layer Masks Ignored (?)
  };
  m_myhDC = ::GetDC(m_hWnd); // Gets A Device Context For The Window
  PixelFormat = ChoosePixelFormat(m_myhDC, &pfd); // Finds The Closest Match To The Pixel Format We Set Above
  if (!PixelFormat)
  {
  ::MessageBox(0,"Can't Find A Suitable PixelFormat.","Error",MB_OK|MB_ICONERROR);
  PostQuitMessage(0);
  // This Sends A 'Message' Telling The Program To Quit
  return false ; // Prevents The Rest Of The Code From Running
  }
  if(!SetPixelFormat(m_myhDC,PixelFormat,&pfd))
  {
  ::MessageBox(0,"Can't Set The PixelFormat.","Error",MB_OK|MB_ICONERROR);
  PostQuitMessage(0);
  return false;
  }
  m_hRC = wglCreateContext(m_myhDC);
  if(!m_hRC)
  {
  ::MessageBox(0,"Can't Create A GL Rendering Context.","Error",MB_OK|MB_ICONERROR);
  PostQuitMessage(0);
  return false;
  }
  
  if(!wglMakeCurrent(m_myhDC, m_hRC))
  {
  ::MessageBox(0,"Can't activate GLRC.","Error",MB_OK|MB_ICONERROR);
  PostQuitMessage(0);
  return false;
  }
  // Now that the screen is setup we can
  // initialize OpenGL();
  InitGL();
  return true;
  }
  Next you'll want to disable the WM_ERASEBACKGROUND message. Without disabling this you'll see a nasty flicker in your applications. Do this by returning FALSE from the OnEraseBkgnd() method. Your view won't have this by default so you'll need to right-click on the view class in the workspace window. Next select "Add Windows Message Handler" from the pop-up menu.In the Dialog that opens up look in the list box for the WM_ERASEBKGND message. Finally hit the "Add and Edit" button to add this
  message handler and edit it. This will point you at the newly created message handler for that message, aka
  OnEraseBkgnd(CDC* pDC).
  Getting back to disabling this method: in the message handler just return FALSE. Make itlook like this.
  BOOL CMfc_basicView::OnEraseBkgnd(CDC* pDC)
  {
  return FALSE;
  }
  Alright, we're almost half-way there. You'll have noticed that in SetupPixelFormat I called a function InitGL(). Let's add that function to your View class. This will initialize OpenGL and you can modify it as you see
  fit.
  void CMfc_basicView::InitGL()
  {
  // Enables Depth Testing
  glEnable(GL_DEPTH_TEST);
  // Enable the point size for selected points
  glPointSize(5.0f);
  // This Will Clear The Background Color To Black
  glClearColor(.4, 0.2, 0.0, 0.0f);
  // Reset the current projection matrix
  SetProjection();
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  //Enable back face culling, defaults to Clock wise vertices.
  glEnable(GL_CULL_FACE);
  glEnable(GL_COLOR_MATERIAL);
  glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  glShadeModel(GL_SMOOTH);
  glPolygonMode(GL_FRONT, GL_FILL);
  }
  Next we'll want to write some code to handle the window resizing. In order to do this we add some code to another message handler. This time it's the OnSize Message Handler. Right-click as before and follow the same steps to create the OnSize Message handler. You'll notice the "UINT nType, int cx, int cy" paramaters that get passed into the method. These are the new width and height, cx and cy, of the window. We can use these to adjust our viewport and
  projection matrices like accordingly.
  void CMfc_basicView::OnSize(UINT nType, int cx, int cy)
  {
  CView::OnSize(nType, cx, cy);
  
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  // Make the rendering context current
  wglMakeCurrent(m_myhDC,m_hRC);
  // Reset The Current Viewport And Perspective Transformation
  glViewport(0, 0, cx, cy);
  
  m_height= cy;
  m_width = cx;
  
  // Calculate The Aspect Ratio Of The Window
  gluPerspective(60.0f,
  (GLfloat)cx/(GLfloat)cy,
  0.1f,
  1000.0f);
  }
  Ok, we just have one more function to add and that's this one.
  void CMfc_basicView::SetProjection()
  {
  
  glViewport(0, 0, m_width, m_height);
  
  // Reset The Projection Matrix
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  // It's a perspective projection
  // Calculate The Aspect Ratio Of The Window
  gluPerspective(60.0f,(GLfloat)m_width/(GLfloat)m_height, 0.1f,3000.0f);
  }
  This is just a simple function I use sometimes to reset the projection matrices. It's up to you if you want to include this in your project.
  So where do we put the Drawing code? Before we do that let's link in the OpenGL libraries we need. Go the Project Menu and select Settings. Hit the Link tab and add the following statements to the end of the library entries.
  opengl32.lib glu32.lib glut.lib glaux.lib
  Next we want to add the call to SetupPixelFormat. The best time to do this is on window creation, just like you'd do in a normal win32 application. For this we'll make use of the OnCreate message handler. Add this as you've added the other message handlers. Here's the code to call the SetupPixelFormat function. Note I've added the call to wglMakeCurrent(NULL,NULL). This gives up the context to other processes.
  int CMfc_basicView::OnCreate(LPCREATESTRUCT lpCreateStruct)
  {
  if (CView::OnCreate(lpCreateStruct) == -1)
  return -1;
  
  SetupPixelFormat();
  wglMakeCurrent(NULL,NULL);
  
  return 0;
  }
  Let's compile, hit Ctrl-F5 and you should get a working application that just draws a window. It won't even clear the screen for you. We need to add some drawing code. I've added a call to draw a few Toruses.
  /
  // CMfc_basicView drawing
  // This function draws three toruses on the screen and rotates them
  // Replace this with your own drawing code.
  //
  void CMfc_basicView::OnDraw(CDC* pDC)
  {
  // Integer declared as static so the value is maintained
  static int i=0;
  // Increase i, this is the rotation value.
  i += 1.11;
  
  // Make the rendering context current as we're about to
  // draw into it
  wglMakeCurrent(m_myhDC,m_hRC);
  
  // Clear the screen and the depth buffer
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  
  // Reset the model matrix
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  
  // Translate to a suitable position
  glTranslatef(0,0,-100);
  // We're going to draw using this color. ( an orange )
  glColor3f( 0.89f, 0.36f, 0.0f);
  // Rotate to some angle (i)
  glRotatef(i, 1,0,0);
  glRotatef(i ,0,1,0);
  glRotatef(i ,0,0,1);
  // Draw the first torus.
  auxSolidTorus( 8,50);
  // Rotate some more and draw the second.
  glRotatef(i ,0,1,0);
  glRotatef(i ,0,0,1);
  auxSolidTorus( 8,30);
  // Rotate some more and draw the third
  glRotatef(-i ,0,1,0);
  glRotatef(i ,0,0,1);
  auxSolidTorus( 8,10);
  
  // Swap the virtual screens
  SwapBuffers(m_myhDC);
  // Invalidate the window as we're
  // ready to draw another frame
  Invalidate(FALSE);
  
  }
  And that's it. Ths application is complete. Obviously this can be improved, the app only draws three toruses. It also uses a lot of CPU in idle time. I left these features as they are since I only wanted to illustrate the use of OpenGL with MFC. If you'd like to experiment, take this code and run with it. I'll be happy to post anything you come up with. I hope found this TUT useful, if you did let me know.
  TrackBacks
  Comments
   Nizar: Hi,
  Great tutorial.
  thanks.
  One suggestion.
  if you can override the OnSize function of the Mainframe, the resize, maximize and minimize issues will be solved.
  Example.
  void CMainFrame::OnSize(UINT nType, int cx, int cy)
  {
  CFrameWnd::OnSize(nType, cx, cy);
  RedrawWindow();
  // TODO: Add your message handler code here
  }
   Godwin: Excellent resource, just what I was looking for.
  Aristotel: Thanks for this nice tutorial! :)
   Bob: Nice work Francis, thanks a lot. There is just something that puzzles me however: If you click on the MAXIMIZE box button on the title bar, the application fills the whole screen but the toolbar of the mainframe seems to have an issue to redraw properly. If yo MINIMIZE the mainframe again and move the window a bit, it repaints fine. I tried on another computer with a powerful video card and got the same issue. Has anyone experienced this also? If yes, how to fix it...?
   Francis: Lam: Check http://nehe.gamedev.net, they should have what you're looking for.
   lam: i'm want to have some code to using mouse in Opengl with visual c++ 7.0
   santosh: good effort. but some illustrative example
  with picture would serve the purpose more
  efficiently.
   ceinx: thanks a lot....it realy help me.....
   Noob: Really good TUT. I have a question besides the TUT.
  Is there any tools that can generate this code(somth like a 3d wizard ?)? and Is there a way to import somehow a 3dsMAX generated 3d object without drawing it myself(maybe with somekind of plug in that exports to smth compatible)?
   Ceres629: Nevermind, I figured it out... great tutorial though good work ;)
   Ceres629: Great tutorial and it worked which is great but i dont really know how to draw my scenes, everything I try just gives me a black screen. Is there something I need to change with the view?
   Patrick Kellen: Good tutorial for me. I struggled through some of the message handler stuff, but I had no previous MFC experience, just OpenGL.
   Priyadarshi : Really cool stuff!!
   Hanns: Great Tutorial, but to start I had to change glut.lib to glut32.lib. Also the rotation was to fast. So I changed the integer i in OnDraw to a float and set it to 0.1 and then it was okay.
   pskumaran: simply superb.
   Francis: Hi Andrew. Ive no idea why Release config doesnt work for you but Id suspect its your libs. Microsoft vs OpenGL versions are not exactly alike as I recall.
   Andrew Senin: Hello Francis! Its a really useful article. But there is something wrong with your project, I think. I downloaded it, started. Everything was fine but after I had changed configuration from debug to release all I saw was the black window. So, it did not show anything in release configuration. I tested it on 2 computers with similar results: debug works, release does not. Perhaps it is because I changed library files to opengl32.lib glu32.lib (I use standard realization of OpenGL from Microsoft). Do you have any ideas why it does not work in release? Thank you. –Andrew.
   Nishant Mehta: Thanks a lot! Absolutely great....even better than whats given in the opengl superbible.
   LApko Michael: Thanks a lot!!!
  Very good tutorial!
  I saw many tut of Mfc and OpenGl but they were too much complicated. But you exactly what i need. Thanks.
  Just one request, may I?
  Would you like to write tut about making menu and control dialog toolbar as simply as this tutorial.
   Ernest: Hi, very good tutorial! Thanks to people like you i have started to dive in this OpenGLs world. Thank you!
  HUYOO: I have just modified this article(which is post in my favorites,not in my articles),and only remain the introduction and the link .
  i am getting out to work these days,so i am sorry i do not reply your comments immediatly~~~
  Francis: Ryan:
  No sorry, you can email me the code if you want and if I get a spare min Ill take a look.
   Ryan : Francis, Im trying to write a demo very similar to what you show here... but when I call Invalidate() in my OnDraw() handler, the application stops rendering after the first pass. Any thoughts on what could be causing this?
   Ryan : Francis, Im trying to write a demo very similar to what you show here... but when I call Invalidate() in my OnDraw() handler, the application stops rendering after the first pass. Any thoughts on what could be causing this?
   Francis: CcaptnB:
  Youd have to first capture where the mouse click happens (X,Y), then track an offset as teh mouse is moved. Depending on the delta between the current and clicked positions of the mouse, youd change the rotation or transformation of the model. I did this in the OGLM tool which is elsewhere on the site. Look for the code that renders the quadrants of the model. This exact functionality is done in the quadrants.
   CcaptnB: Hi, nice tutorial! Im just wondering how I could manage mouse events to zoom, pan or rotate my models in your example.
   Francis: CHE -- Sorry, the CPU is fairly cycle hungry as the screen is constantly invalidated. You can regulate this with the WM_TIMER event. Enjoy.
   Simone: Great! Its do!
   Gustavo: Esto es una porqueria no funciona
   CHE: Hi Francis,
  Ive just read your OpenGL-MFC turorial and executed successfully the program. But the problem is, that it is too CPU-cycles hungry. The CPU is always 100% busy, although OpenGL just clears the window. Why is it so?? Thanks a lot.
  Che
   hind: how we program games
   Francis: For Selection, read these articles:
  http://www.francisshanahan.com/default.aspx?ctype=Articles&top=OpenGL%20Selection
   Amol: I want to select object in openGL.
  I have find no of things.But code on different sites are not easy to understand. Please help me.
   Francis: NOTE: To run the source code, you need the GLUT available here:
  http://www.opengl.org/resources/libraries/glut.html
   Kevin Wang: Sir,
  I downloaded your sample code and compilered it, but got error message.
  The error message is like that: c:/tempformfc /stdafx.h(22): fatal error C1083: Cannot open include file:
  gl/glut.h: No such file or directory. I dont know how to solve this problem. Could you give me some help in this way? Thanks.
   Francis: Fixed the link. Click away.
   Adnan: the link for downloading the tutorial is not working
   Francis: Amol: you dont include a lib, you link it. Make sure glut.lib is in your /includes directory.
  Zaheer: why dont you just select the whole thing, copy it into notepad and print?
   Zaheer: I want to read this tutorial. How can I can dowload it.
   Amol: I can,t include glut.lib. It gives me linking error.
  If I dont include glut.lib then I cant see anything on windpow except brown colour.

本文转自
http://www.francisshanahan.com/detail.aspx?cid=137
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值