Cai Mao, mailbox 9693, Xi'an Jiao Tong University
---- Scientific computing visualization, computer animation and virtual reality are currently three hot spots in computer graphics. The core of these three hot spots is 3D Realistic Graphics. Since OpenGL (opengraphicslibrary) is cross-platform, simple, efficient, and fully functional, it has become a de facto industrial standard in 3D graphics production methods. Since windowsnt3.51 supports OpenGL on the microcomputer platform, Microsoft has continuously provided the OpenGL development environment in windows95osr2 and windowsnt4.0. Visual c ++ has fully supported OpenGL APIs since version 4.2, making "Popularization" of the 3D world inevitable.
---- OpenGL support in Windows
---- Anyone with windows programming experience knows that in windows, the corresponding functions must be called through the device context (devicecontext short for DC) for drawing with GDI; and similar for drawing with OpenGL, openGL draws a 3D image by using renderingcontext (RC. In Windows, the window and device context support the "bitmap format" (pixelformat) attribute, which is consistent with that in RC. You only need to establish a connection with a DC when creating an RC (RC can only be created through a DC with a bitmap format already in place ), openGL functions can be drawn to the corresponding display device through the DC corresponding to RC. Note the following:
---- 1. A thread can have only one rendering context (RC). That is to say, if you map different devices in one thread, you can only replace the DC corresponding to the RC, the RC process remains unchanged. (Of course, it is okay to delete the old RC and create a new one). In contrast, an RC can only belong to one thread and cannot be shared by different threads at the same time.
---- 2. Setting the DC bitmap format is equal to setting the corresponding window bitmap format, and once the DC and window bitmap formats are determined, they cannot be changed. This can only be improved in later Windows versions.
---- 3. although one RC can replace the DC, only one DC can be used at any time (this DC is called the current DC of the RC ), however, a window allows multiple DC diagrams so that multiple threads can use multiple RC to execute OpenGL operations on the window.
---- 4. The current OpenGL version in Windows imposes certain limitations on OpenGL and GDI drawing on the same DC. When OpenGL is used to generate animations using dual cache, the GDI function cannot be used to map images to the DC.
---- 5. It is not recommended that you use ansic to write OpenGL programs in windows. Although such programs have cross-platform portability (for example, many SGI examples), they cannot take advantage of many features of the Windows operating system and are of little practical value.
---- Use VC to compile OpenGL programs
---- After the above analysis, it is obvious to use VC to call the OpenGL plotting method. The procedure is as follows:
---- 1. First set the pixelformat attribute of the display device DC. This is done by filling in a pixelformatdescriptor structure (for the meaning of the data in pixelformatdescriptor, refer to the help information of Vc). This structure determines the attributes of physical devices drawn by OpenGL, for example, if the pfd_doublebuffer bit in the data item dwflags in the structure is not set (set to 1), the OpenGL command drawn on the DC of the device cannot use double buffering for animation. Some bitmap formats (pixelformat) are supported by DC, but some DC do not. Therefore, the program must first use choosepixelformat to select the most similar bitmap format supported by DC to the specified bitmap format, and then use setpixelformat to set the bitmap format of DC.
---- 2. Use the device DC to establish the rendering context RC (wglcreatecontext) so that the RC can establish a connection with the DC (wglmakecurrent ).
---- 3. Call OpenGL function plotting. Since the threads correspond to RC one by one, the parameters of OpenGL functions do not specify the RC handle (handle) of this thread)
---- 4. after the rendering, the connection between the current thread and the rendering context is broken by setting the RC of the current thread to null (: wglmakecurrent (null, null, disconnect from the DC. At this time, the validity of the RC handle is not clearly stated in Microsoft's own documents. Therefore, when you delete the RC later, you must first determine the validity of the following RC handle (if (m_hrc ):: wgldeletecontext (m_hrc );). Release (releasedc) or delete (deletedc) DC as needed
---- Program description
---- The attached program uses MFC to complete a simple OpenGL drawing, and draws a solid Circular Ball with illumination using the OpenGL auxiliary library. The functions of OpenGL are not explained here. We only provide a brief description of the content that needs to be paid attention to when compiling OpenGL Using MFC:
---- 1. Once a DC bitmap format is set, the bitmap format of the window associated with the DC is set accordingly. If this window contains child windows or has brother windows, the bitmap format of these brother/child windows is not set to the same format as that of the corresponding RC, and OpenGL is prone to errors when plotting on them. Therefore, the Windows drawn by OpenGL must have ws_clipchildren and ws_clipsiblings styles. in the program, loadframe (idr_mainframe, ws_overlappedwindow | ws_clipchildren | ws_clipsiblings, null, null) is used in the con ); specifies the style of the main window.
---- 2. In ansic's OpenGL programming, auxreshapefunc defines the callback function for setting the OpenGL viewport size and drawing size. In MFC, The wm_siz message processing function should be used. In ansic OpenGL programming, eauxmainloop defines the callback function for plotting. In MFC, The wm_paint message processing function is used to process the message. Correspondingly, the keyboard and mouse processing functions defined by OpenGL should be responded by corresponding Windows processing functions.
---- 3. OpenGL uses the glclear function to refresh the background. Therefore, windows should be disabled to refresh the background. Otherwise, Windows automatically sends wm_erasebkgnd when the window needs to be re-painted, and the default processing function uses a white background brush. When OpenGL uses a background color that is not white, a frame of white flashes. This is especially evident in animation. In the program, you only need to disable the message processing of the parent window class in the message processing function of wm_erasebkgnd. Simply return a true value.
---- 4. Due to the cross-platform nature of OpenGL, it must use the operating system's palette. Therefore, if gl_index_mode is used for plotting, you must use VC to define the color palette. However, the gl_rgba_mode mode is generally more convenient, and the gl_index_mode mode is rarely used.
---- 5. During OpenGL plotting, the DC corresponding to RC cannot be deleted or released.
---- 6. Because OpenGL takes up DC for a long time, it is best to set the drawing window class to cs_owndc. This attribute is not set in the default window class style of MFC. in the program, you have registered a window class in the precreatewindow method of the Main Window C ++ class. Besides setting the cs_owndc attribute, cs_hredraw, cs_vredraw, and cs_savebits are also set. Cs_hredraw and cs_vredraw are set to generate the wm_paint message when the window is scaled, and the OpenGL view and drawing size are corrected. Because OpenGL drawing requires a lot of computation, cs_savebits is set to avoid generating wm_paint messages when the OpenGL window is hidden and filled with memory-stored images, so as to exchange computing time with space consumption.
---- 7. This program does not handle errors in OpenGL functions. If an OpenGL error occurs, an error code is returned, which does not throw an exception. After a function error occurs, the subsequent function generally does not have an exception, but only returns an error code. If you are not careful, you may ignore some errors. It is difficult to judge whether an error is made to every OpenGL function. Therefore, when programming, you should be very careful with OpenGL functions.
---- Reference books:
---- Openglprogrammer's sguide sgiinc.
---- OpenGL 3D graphic program design by Liao duoduo and Zhang huajun, Planet map publishing house
---- Visual c ++ 5.0 online help
---- Appendix:
---- When running the program, make sure that opengl32.dll, Glu. dll, and Glaux. dll are in the Windows System directory. If you cannot find these files, copy them from the windows95osr2 host. You do not need to register the library information when running OpenGL. When running a program in VC studio, OpenGL must be added to the project file. h. h. Glaux. H and OpenGL. lib, Glu. lib, Glaux. lib. These files are provided by VC.
---- Main window class definition (openglwnd. h ):
# If! Defined (afx_openglwnd_h1_3fb1ab28_0e70
_ 11d2_9aca_48543300e17d1_encoded _)
# Define afx_openglwnd_h1_3fb1ab28_0e70_11d2
_ 9aca_48543300e17d1_included _
# If _ msc_ver> = 1000
# Pragma once
# Endif // _ msc_ver >=1000
# Include <afxwin. h>
# Include "simpleglapp. H"
# Include "resource. H"
// Openglwnd. h: header file
//
///////////////////////////////////////
//////////////////////////////////////
// Copenglwnd Frame
Class copenglwnd: Public cframewnd
{
Declare_dyncreate (copenglwnd)
Public:
Copenglwnd ();
// Protected constructor used by Dynamic Creation
Protected:
Hglrc m_hrc;
Cclientdc * m_pdc;
// Attributes
Public:
// Operations
Public:
// Overrides
// Classwizard generated virtual function overrides
// {Afx_virtual (copenglwnd)
Protected:
Virtual bool precreatewindow (createstruct & CS );
//} Afx_virtual
// Implementation
Public:
Virtual ~ Copenglwnd ();
// Generated message map Functions
// {Afx_msg (copenglwnd)
Afx_msg int oncreate (maid );
Afx_msg void onsize (uint ntype, int CX, int CY );
Afx_msg void ondestroy ();
Afx_msg bool onerasebkgnd (CDC * PDC );
Afx_msg void onpaint ();
//} Afx_msg
Declare_message_map ()
};
///////////////////////////////////////
//////////////////////////////////////
// {Afx_insert_location }}
// Microsoft developer studio will insert
Additional Declarations immediately before the previous line.
# Endif //! Defined (afx_openglwnd_h1_3fb1ab28 _
0e70_11d2_9aca_48543300e17d1_encoded _)
Implementation of the main window class (openglwnd. cpp ):
// Openglwnd. cpp: implementation file
//
# Include "stdafx. H"
# Include "openglwnd. H"
# Include "simpleglapp. H"
# Include "Gl/Glu. H"
# Include "Gl/Gl. H"
# Include "Gl/Glaux. H"
# Ifdef _ debug
# Define new debug_new
# UNDEF this_file
Static char this_file [] = _ file __;
# Endif
///////////////////////////////////////
//////////////////////////////////////
// Copenglwnd
Implement_dyncreate (copenglwnd, cframewnd)
Copenglwnd: copenglwnd ()
{
M_pdc = NULL;
M_hrc = 0;
Loadframe (idr_mainframe, ws_overlappedwindow
| Ws_clipchildren | ws_clipsiblings
, Null, null );
}
Copenglwnd ::~ Copenglwnd ()
{
}
Begin_message_map (copenglwnd, cframewnd)
// {Afx_msg_map (copenglwnd)
On_wm_create ()
On_wm_size ()
On_wm_destroy ()
On_wm_erasebkgnd ()
On_wm_paint ()
//} Afx_msg_map
End_message_map ()
Bool copenglwnd: precreatewindow (createstruct & CS)
{
// Todo: add your specialized
Code here and/or call the base class
CS. lpszclass = afxregisterwndclass (cs_dblclks |
Cs_hredraw |
Cs_vredraw |
Cs_savebits |
Cs_noclose |
Cs_owndc
, Afxgetapp ()-> loadstandardcursor (idc_arrow), 0,
Afxgetapp ()-> loadstandardicon (idi_application ));
Return cframewnd: precreatewindow (CS );
}
Int copenglwnd: oncreate (maid)
{
If (cframewnd: oncreate (lpcreatestruct) =-1)
Return-1;
Int pixelformat;
M_pdc = new cclientdc (this); // plot in customer Zone
Assert (m_pdc! = NULL );
Static pixelformatdescriptor PFD =
{
Sizeof (pixelformatdescriptor), // fixed value
1, // fixed value
Pfd_draw_to_window | // support window
Pfd_support_opengl | // support OpenGL
Pfd_type_rgba, // rgba mode, no color palette required
16, // The program runs in a 16-bit color
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
32, // 32-bit Z-Buffer
0, // No stencel Buffer
0, // No auxiliary Buffer
Pfd_main_plane, // main layer
0, // Reserved
0, 0, 0 // layer masks ignored
};
If (pixelformat = choosepixelformat (m_pdc-> getsafehdc (), & PFD) = 0)
{
MessageBox ("the bitmap structure close to PFD cannot be found on the DC ");
Return-1;
}
If (setpixelformat (m_pdc->
Getsafehdc (), pixelformat, & PFD) = false)
{
MessageBox ("the bitmap structure cannot be set on the DC ");
Return-1;
}
M_hrc = wglcreatecontext (m_pdc-> getsafehdc ());
Wglmakecurrent (m_pdc-> getsafehdc (), m_hrc );
Glcleardepth (1.0f );
Glenable (gl_depth_test );
Glmatrixmode (gl_projection );
Glloadidentity ();
Glmatrixmode (gl_modelview );
Return 0; // the OpenGL window is successfully constructed.
}
Void copenglwnd: onsize (uint ntype, int CX, int CY)
{
Cframewnd: onsize (ntype, CX, CY );
// Todo: add your message handler code here
If (CY> 0)
{
Glviewport (0, 0, CX, CY );
Glmatrixmode (gl_projection );
Glloadidentity ();
If (CX <= CY)
Glortho (-3.0, 3.0,-3.0 * (glfloat) CX/(glfloat) cy,
3.0 * (glfloat) CX/(glfloat) cy,-3.0, 3.0 );
Else
Glortho (-3.0, 3.0,-3.0 * (glfloat) cy/(glfloat) Cx,
3.0 * (glfloat) cy/(glfloat) Cx,-3.0, 3.0 );
Glmatrixmode (gl_modelview );
}
}
Void copenglwnd: ondestroy ()
{
Cframewnd: ondestroy ();
: Wglmakecurrent (null, null );
If (m_hrc)
: Wgldeletecontext (m_hrc );
If (m_pdc)
Delete m_pdc;
// Todo: add your message handler code here
}
Bool copenglwnd: onerasebkgnd (CDC * PDC)
{
// Todo: add your message handler code here and/or call default
Return true;
// Return cframewnd: onerasebkgnd (PDC );
}
Void copenglwnd: onpaint ()
{
Cpaintdc DC (this); // device context for painting
Glfloat light_position [] = {2.0f, 0.0f, 4.0f, 0.0f };
// Todo: add your message handler code here
Glclearcolor (0.0f, 0.0f, 0.0f, 1.0f );
Glclear (gl_color_buffer_bit | gl_depth_buffer_bit );
Glpushmatrix ();
Gltranslatef (0.0f, 0.0f,-2.0f );
Gllightfv (gl_light0, gl_position, light_position );
Glable (gl_lighting );
Glable (gl_light0 );
Gldepthfunc (gl_less );
Glenable (gl_depth_test );
Auxsolidsphere (1.0 );
Glpopmatrix ();
Glfinish ();
// Do not call cframewnd: onpaint () for painting messages
}
Application class definition (simpleglapp. h ):
# If! Defined (afx_simpleglapp_hsf-3fb1ab29
_ 0e70_11d2_9aca_48543300e17d1_encoded _)
# Define afx_simpleglapp_hsf-3fb1ab29_0e70
_ 11d2_9aca_48543300e17d1_encoded _
# If _ msc_ver> = 1000
# Pragma once
# Endif // _ msc_ver >=1000
// Simpleglapp. h: header file
//
# Include <afxwin. h>
# Include "openglwnd. H"
# Include "resource. H"
///////////////////////////////////////
//////////////////////////////////////
// Csimpleglapp thread
Class csimpleglapp: Public cwinapp
{
Declare_dyncreate (csimpleglapp)
Public:
Csimpleglapp ();
// Protected constructor used by Dynamic Creation
// Attributes
Public:
// Operations
Public:
// Overrides
// Classwizard generated virtual function overrides
// {Afx_virtual (csimpleglapp)
Public:
Virtual bool initinstance ();
Virtual int exitinstance ();
//} Afx_virtual
// Implementation
Public:
Virtual ~ Csimpleglapp ();
// Generated message map Functions
// {Afx_msg (csimpleglapp)
Afx_msg void onappexit ();
//} Afx_msg
Declare_message_map ()
};
///////////////////////////////////////
//////////////////////////////////////
// {Afx_insert_location }}
// Microsoft developer studio will insert
Additional Declarations
Immediately before the previous line.
# Endif //! Defined (afx_simpleglapp_hsf-3fb1ab29 _
0e70_11d2_9aca_48543300e17d1_encoded _)
Implementation of the application class (simpleglapp. cpp ):
// Simpleglapp. cpp: implementation file
//
# Include "stdafx. H"
# Include "simpleglapp. H"
# Include "openglwnd. H"
# Ifdef _ debug
# Define new debug_new
# UNDEF this_file
Static char this_file [] = _ file __;
# Endif
///////////////////////////////////////
//////////////////////////////////////
// Csimpleglapp
Implement_dyncreate (csimpleglapp, cwinapp)
Csimpleglapp: csimpleglapp ()
{
}
Csimpleglapp ::~ Csimpleglapp ()
{
}
Bool csimpleglapp: initinstance ()
{
// Todo: Perform and per-thread initialization here
M_pmainwnd = new copenglwnd ();
M_pmainwnd-> showwindow (m_ncmdshow );
M_pmainwnd-> updatewindow ();
Return true;
}
Int csimpleglapp: exitinstance ()
{
Return cwinapp: exitinstance ();
}
Begin_message_map (csimpleglapp, cwinapp)
// {Afx_msg_map (csimpleglapp)
On_command (id_app_exit, onappexit)
//} Afx_msg_map
End_message_map ()
///////////////////////////////////////
//////////////////////////////////////
// Csimpleglapp message handlers
Void csimpleglapp: onappexit ()
{
// Todo: add your command handler code here
Cwinapp: onappexit ();
}
Csimpleglapp simpleglapp;