Summary of OpenGL in MFC (1)

Source: Internet
Author: User
3D display models should be drawn in the project, so OpenGL should be used, and the models should be used in MFC and ActiveX in MFC, and given the setting of their main program framework, conventional methods may not be implemented. Therefore, I have checked a lot of information and will summarize it here. First, summarize the most basic things.

1. According to the logic of the lecture, let's talk about the principles first ~

GDI draws through the device context ("DC"), while OpenGL renders the rendering context ("RC "). Each GDI Command needs to be passed to a DC. Unlike GDI, OpenGL uses the current rendering description table (RC ). Once a current RC is specified in a thread, all subsequent OpenGL commands in this thread use the same current RC. Although multiple RC can be used in a Single Window, there is only one current RC in a single thread. Next I will first generate an OpenGL RC and make it the current RC, which will be divided into three steps:
Set the window pixel format; generate RC; set it to the current RC.

Ii. Basic OpenGL framework in MFC

First, add the OpenGL file and Library to the project.
Add the following header files
# Include <GL \ Gl. h>
# Include <GL \ Glu. h>

Add the following library files (not always used)
Opengl32.lib
Glu32.lib
GLUT. Lib
Glaux. Lib

After the preparation is complete, configure the environment and initialize the environment ~
1. Rewrite the onprecreate function and add member functions and member variables to the View class.
OpenGL requires ws_clipchildren (Windows style used to create the parent window, used to crop the area covered by the Child Window during re-painting) and ws_clipsiblings (Windows style used to create the Child Window, used to crop the area covered by other subwindows during repainting.

Rewrite onprecreate as follows:

<span style="font-size:14px;">BOOL COpenGLDemoView::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);}</span>

2. Define the pixel format of the window

The first step to generate an RC is to define the pixel format of the window. The pixel format determines how the displayed image is displayed in the memory. Parameters controlled by the pixel format include: color depth, buffer mode, and supported painting interfaces. These parameters are set below. First, add a protected member function bool setwindowpixelformat (HDC) and a protected member variable: int m_glpixelindex in the copengldemoview class;

Edit the Code as follows:

<Span style = "font-size: 14px;"> bool copengldemoview: setwindowpixelformat (HDC) {// define the pixel format of the window pixelformatdescriptor pixeldesc = {sizeof (elpixformatdescriptor ), 1, strong | pfd_support_opengl | pfd_doublebuffer | pfd_support_gdi, hour, 24, 0, 0, 0, 0, 0, 0, 32, 0, 0, pfd_main_plane, 0, 0, 0}; this-> m_glpixelindex = choosepixelformat (HDC, & pixeldesc); If (this-> m_glpixelindex = 0) {This-> m_glpixelindex = 1; if (describepixelformat (HDC, this-> m_glpixelindex, sizeof (pixelformatdescriptor), & pixeldesc) = 0) {return false;} If (setpixelformat (HDC, this-> m_glpixelindex, & pixeldesc) = false) {return false;} return true ;}</span>

Code explanation:
Now let's take a look at the several pixel formats provided by describe-pixelformat and explain the Code:
Pixelformatdescriptor includes all the information that defines the pixel format.
Dwflags defines devices and interfaces compatible with Pixel formats.

Generally, OpenGL releases do not include all flags ). Wflags can receive the following flags:

Pfd_draw_to_window enables you to draw images in Windows or other device windows;
Pfd_draw_to_bitmap enables bitmap painting in memory;
Pfd_support_gdi enables you to call the GDI function (Note: If pfd_doublebuffer is specified, this option will be invalid );
Pfd_support_opengl enables you to call OpenGL functions;
Pfd_generic_format if this pixel format is supported by the Windows GDI function library or by a third-party hardware device driver, you need to specify this item;
Pfd_need_palette tells the buffer whether a color palette is required. This program assumes that the color is a 24 or 32-bit color and does not overwrite the color palette;
Pfd_need_system_palette indicates whether the buffer zone regards the system palette as part of its own palette;
Pfd_doublebuffer indicates that the dual-buffer is used (Note: GDI cannot draw in the window where the dual-buffer is used );
Pfd_stereo indicates whether the Left and Right buffers are organized by stereo images.

Pixeltype defines the display color. Pfd_type_rgba indicates that each bit group represents the values of the red, green, and blue components. Pfd_type_colorindex indicates that each group represents the index value in the color search table. This example uses the pfd_type_rgba method.
● Ccolorbits defines the number of digits of a specified color. For rgba, the number of digits is the number of digits in the red, green, and blue components of the color. For the color index value, it refers to the number of colors in the table.
● Credbits, cgreenbits, cblue-bits, and calphabits are used to indicate the digits used by each corresponding component.
● Credshift, cgreenshift, cblue-shift, and calphashift are used to indicate the digits occupied by the offset of each component from the color.

Once our structure is initialized, we want to know the most similar system pixel format. We can do this:

M_hglpixelindex = choosepixelformat (HDC, & pixeldesc );
Choosepixelformat accepts two parameters: HDC and pixeldesc. This function returns the index value in this pixel format. If 0 is returned, it indicates that the request fails. If the function fails, we only set the index value to 1 and use describepixelformat to get the pixel format description. If you apply for an unsupported pixel format, the choose-pixelformat will return the closest value to the pixel format you requested. Once we get an index value in pixel format and the corresponding description, we can call setpixelformat to set the pixel format and set it only once.
3. Generate a rendering description table (RC)
Now the pixel format has been set. Our next step is to generate the rendering description table (RC) and make it the current rendering description table. Add a protected member function bool createviewglcontext (HDC) to copengldemoview, and add a protected member variable hglrc m_hglcontext; hglrc is a handle pointing to rendering context.
<Span style = "font-size: 14px;"> bool copengldemoview: createviewglcontext (HDC) {This-> m_hglcontext = wglcreatecontext (HDC ); if (this-> m_hglcontext = NULL) {// return false if creation fails;} If (wglmakecurrent (HDC, this-> m_hglcontext) = false) {// select the current RC failure return false;} return true ;}</span>
4. Call this function in the oncreate function:
<span style="font-size:14px;">int COpenGLDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct) {    if (CView::OnCreate(lpCreateStruct) == -1)        return -1;        // TODO: Add your specialized creation code here    HWND hWnd = this->GetSafeHwnd();        HDC hDC = ::GetDC(hWnd);    if(this->SetWindowPixelFormat(hDC)==FALSE)    {        return 0;    }    if(this->CreateViewGLContext(hDC)==FALSE)    {        return 0;    }    return 0;} <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span></span>
5. Add the message processing function ondestroy () of wm_destroy to make it as follows:
<span style="font-size:14px;">void COpenGLDemoView::OnDestroy() {    CView::OnDestroy();        // TODO: Add your message handler code here    if(wglGetCurrentContext()!=NULL)    {        wglMakeCurrent(NULL,NULL);    }    if(this->m_hGLContext!=NULL)    {        wglDeleteContext(this->m_hGLContext);        this->m_hGLContext = NULL;    }}   </span>
6. Edit the constructor of copengldemoview as follows:
<span style="font-size:14px;">COpenGLDemoView::COpenGLDemoView(){    // TODO: add construction code here    this->m_GLPixelIndex = 0;    this->m_hGLContext = NULL;}</span>
So far, we have constructed a framework so that the program can draw Images Using OpenGL. You may have noticed that an RC is generated at the beginning of the program and is used from the beginning to the end. This is different from most GDI programs. In the GDI program, DC is generated only when needed, and is released immediately after painting. In fact, RC can do the same, but remember that it takes a lot of processing time to generate an RC. Therefore, to obtain high-performance and smooth images and graphics, it is best to generate only RC once and always use it until the program ends.

Createviewglcontex generates RC and converts it into the current RC. Wglcreatecontext returns an RC handle. Before calling createviewglcontex, you must use setwindowpixelformat (HDC) to set the device-related pixel format. Wglmakecurrent sets RC to the current RC. The DC passed in this function is not necessarily the DC where you generate the RC, but the device context and pixel formats of the two must be consistent. If another RC already exists before wglmakeforcurrent is called, wglmakeforcurrent will overwrite the old RC and set the new RC to the current RC. In addition, you can use wglmakecurrent (null, null) to eliminate the current RC. Delete the rendering description table in ondestroy. Before deleting the RC, you must determine that it is not the current handle. We use wglgetcurrentcontext to check whether a rendering description table exists. If so, use wglmakecurrent (null, null) to remove it. Then you can use wgldelete-context to delete the RC. In this case, it is safe to allow the class to delete the DC. Note: Generally, a single-threaded program is used, and the generated RC is the current RC of the thread. You do not need to pay attention to this. However, if a multi-threaded program is used, we need to pay special attention to this point. Otherwise, unexpected consequences may occur.


3. Give an instance (I will be lazy. I will not compile and execute the data directly from the Internet)
The following is an example of a simple two-dimensional image (this example is based on the above framework ).
Use classwizard to add the onsize function of wmsize to copengldemoview. The Code is as follows:
<span style="font-size:14px;">void COpenGLDemoView::OnSize(UINT nType, int cx, int cy) {    CView::OnSize(nType, cx, cy);        // TODO: Add your message handler code here    GLsizei width,height;    GLdouble aspect;    width = cx;    height = cy;    if(cy==0)    {        aspect = (GLdouble)width;    }    else    {        aspect = (GLdouble)width/(GLdouble)height;    }    glViewport(0,0,width,height);    glMatrixMode(GL_PROJECTION);    glLoadIdentity();    gluOrtho2D(0.0,500.0*aspect,0.0,500.0);    glMatrixMode(GL_MODELVIEW);    glLoadIdentity();}  </span>
Use classwizard to add the onpaint message processing function wm_paint to copengldemoview. The Code is as follows:
<span style="font-size:14px;">void COpenGLDemoView::OnPaint() {    CPaintDC dc(this); // device context for painting        // TODO: Add your message handler code here        // Do not call CView::OnPaint() for painting messages    glLoadIdentity();    glClear(GL_COLOR_BUFFER_BIT);    glBegin(GL_POLYGON);        glColor4f(1.0f,0.0f,0.0f,1.0f);        glVertex2f(100.0f,50.0f);        glColor4f(0.0f,1.0f,0.0f,1.0f);        glVertex2f(450.0f,400.0f);        glColor4f(0.0f,0.0f,1.0f,1.0f);        glVertex2f(450.0f,50.0f);    glEnd();    glFlush();}</span>

The running result of this program is a colorful triangle in the black background.



Here you can see that it is very easy to draw a graph using OpenGL. Only a few simple statements are required to implement powerful functions. If you scale the window, the triangle scales accordingly. This is because onsize defines the coordinates of the views and views through glviewport (0, 0, width, height. The first and second parameters of glviewport are the pixel coordinates in the lower left corner of the view, and the third and fourth parameters are the width and height of the view.
The glmatrixmode in onsize is used to set the matrix mode. It has three options: gl_modelview, gl_projection, and gl_texture. Gl_modelview indicates that the object coordinate system is switched to the human eye coordinate system. Gl_projection indicates switching from the human eye coordinate system to the cropping coordinate system. Gl_texture indicates the transformation from the coordinate system defining the texture to the coordinate system pasting the texture.
  
Iv. Summary
1. If you want to respond to the wm_size message, you must set the view and matrix mode.
2. Try to complete all your drawing work in response to the wm_paint message.
3. It takes a lot of CPU time to generate a rendering description table, so it is best to generate it only once in the program until the program ends.
4. Try to encapsulate your drawing commands in the document class so that you can use the same document in different visual classes to save your programming workload.
5. glbegin and glend must appear in pairs, which is a drawing statement for the elements.
Glpushmatrix () and glpopmatrix () must also appear in pairs. Glpushmatrix () copies the current matrix to the stack. When glpopmatrix is called, the matrix pushed into the stack is restored to the current matrix. You can use glpushmatrix () to precisely Save the current matrix and restore it with glpopmatrix. (In the future, we may summarize the important roles of glpushmatrix () and glpopmatrix ~~)
6. Solve the Problem of flickering screen. We know that when you drag a graph in a window, the image will flash as the image is painted and displayed. Solving this problem in GDI is complicated. by generating a memory DC in the memory, the paint brush is painted in the memory DC, the Flash problem can be solved once bitblt is used to paste the memory DC to the display. In OpenGL, we solve this problem through dual cache. In general, dual cache is common in graphic work software. Dual-cache is a two-cache, one front-end cache and one back-end cache. The drawing is first drawn in the background cache. After the painting is finished, it is switched to the foreground cache so that there will be no flickering. To solve this problem easily, follow these steps:

(1)

Note that the GDI Command is not designed with dual-cache. Change invalidaterect (null) to invalidaterect (null, false ). In this way, the re-painting command of GDI is invalid and the OpenGL command is used for re-painting;

(2)

The pixel format is defined to support dual-Cache (Note: Only one pfd_doublebuffer and pfd_support_gdi can be used, and the two are in conflict ).
Pixeldesc. dwflags =
Pfd_draw_to_window |
Pfd_support_opengl |
Pfd_doublebuffer |
Pfd_stereo_dontcare;

(3)

We have to tell OpenGL to draw images in the background cache and add gldrawbuffer (gl_back) to the last line of the onsize () of the class );

(4)

Finally, we have to change the content cached in the background to the foreground cache, and add swapbuffers (DC. M _ PS. HDC) to the last line of onpaint () of the video class ).

7. Z-buffer problem: To make three-dimensional objects appear smoother and the spatial relationships between the front and back sides are correct, the Z-buffer technology must be used; otherwise, the positions of the front and back sides overlap with each other, cannot be correctly displayed. The Z-buffer zone stores the value of each vertex of an object. This value indicates the distance between the vertex and the human eye. The Z buffer takes a lot of memory and CPU time. To enable the Z buffer, you only need to add the glable (gl_depth_test) at the end of onsize (). Remember: Use the glclear (gl_depth_buffer_bit) statement to clear the Z buffer before each re-painting.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.