Windows 形式中的 OpenGL (c++) - 缓冲区溢出?

OpenGL in Windows Forms (c++) - Buffer overflows?

我使用 Windows 形式用 c++ 编写了一个程序。我使用两种形式。第一个表单只包含一个按钮。当它被按下时,第二个表格打开。此表单包含一个面板,其中播放简单的 OpenGL 模拟(在 windows 表单提供的计时器的帮助下旋转)。可以通过按第一个窗体中的按钮来关闭和再次打开第二个窗体。这样做的次数越多,3D-OpenGL 对象的旋转速度就越慢。这样做大约 6 次后,3D-OpenGL 对象开始完全疯狂地闪烁。我认为这与我构建的 OpenGL 对象没有被正确销毁并且在某个时刻内存已满(在项目的更复杂版本中它在当前 3D 对象和window 关闭后本应销毁的 3D 对象)。

Here is a video of the Problem.

这里是OpenGL的代码:

namespace OpenGLForm 
    {
        public ref class COpenGL: public System::Windows::Forms::NativeWindow
        {
        public:
            // Position/Orientation of 3D Mesh in Mesh-Viewer Window

            float meshPos_x;
            float meshPos_y;
            float meshPos_z;
            float meshOri_x;
            float meshOri_y;
            float meshOri_z;

            COpenGL(System::Windows::Forms::Panel ^ parentForm, GLsizei iWidth, GLsizei iHeight)
            {
                // initialize all parameter / set pointers (for pointers of type MAT)
                meshPos_x = 0.0;
                meshPos_y = 0.0;
                meshPos_z = -2.0;
                meshOri_x = -63.0;
                meshOri_y = 0.0;
                meshOri_z = 0.0;

                CreateParams^ cp = gcnew CreateParams;
                m_hDC = GetDC((HWND)parentForm->Handle.ToPointer());

                System::String^ filename = "C:/Advantech/Desktop/Const.txt";
                System::IO::StreamWriter^ csvWriter = gcnew System::IO::StreamWriter(filename, false, System::Text::Encoding::UTF8);
                csvWriter->Write("Const");
                csvWriter->Close();

                if(m_hDC)
                {
                    MySetPixelFormat(m_hDC);
                    ReSizeGLScene(iWidth, iHeight);
                    InitGL();
                }

            }

            //custom function for transformations
            System::Void Transform(float xTrans, float yTrans, float zTrans, float xRot, float yRot, float zRot)
            {
                //translate object
                glTranslatef(xTrans, yTrans, zTrans);
                //rotate along x-axis
                glRotatef(xRot,1.0f,0.0f,0.0f);
                //rotate along y-axis
                glRotatef(yRot,0.0f,1.0f,0.0f);
                //rotate along z-axis
                glRotatef(zRot,0.0f,0.0f,1.0f);
            }

            System::Void Render(System::Void)
            {
                // Initial Settings
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear screen and depth buffer
                glLoadIdentity();   

                meshOri_z = meshOri_z + 1;
                // Set position and orientation of 3D mesh
                Transform(  meshPos_x, 
                            meshPos_y, 
                            meshPos_z, 
                            meshOri_x,
                            meshOri_y,
                            meshOri_z );

                glScalef( 0.05,  0.05,  0.05 ); 

                int meshSize = 200;
                // create 3D mesh Toplayer
                for (int x = 1; x < meshSize; x++) { 
                  for (int z = 1; z < meshSize; z++) {
                    glBegin(GL_QUADS); 
                    int dm = 1;
                    glColor3f(dm,dm,dm);
                    glVertex3f(  x, z, dm );
                    glVertex3f( (x+1), z, dm );
                    glVertex3f( (x+1), (z+1), dm );
                    glVertex3f(  x, (z+1), dm );
                    glEnd();
                  }
                }
        }


        System::Void SwapOpenGLBuffers(System::Void)
        {
            SwapBuffers(m_hDC) ;
        }

        private:
            HDC m_hDC;
            HGLRC m_hglrc;

        protected:
            ~COpenGL(System::Void)
            {
                System::String^ filename = "C:/Advantech/Desktop/Dest.txt";
                System::IO::StreamWriter^ csvWriter = gcnew System::IO::StreamWriter(filename, false, System::Text::Encoding::UTF8);
                csvWriter->Write("Dest");
                csvWriter->Close();

                wglDeleteContext(m_hglrc);
                DeleteDC(m_hDC);
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                this->DestroyHandle();
            }

            GLint MySetPixelFormat(HDC hdc)
            {
                static  PIXELFORMATDESCRIPTOR pfd=              // pfd Tells Windows How We Want Things To Be
                    {
                        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
                        16,                                     // Select Our 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
                    };

                GLint  iPixelFormat; 

                // get the device context's best, available pixel format match 
                if((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0)
                {
                    MessageBox::Show("ChoosePixelFormat Failed");
                    return 0;
                }

                // make that match the device context's current pixel format 
                if(SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE)
                {
                    MessageBox::Show("SetPixelFormat Failed");
                    return 0;
                }

                if((m_hglrc = wglCreateContext(m_hDC)) == NULL)
                {
                    MessageBox::Show("wglCreateContext Failed");
                    return 0;
                }

                if((wglMakeCurrent(m_hDC, m_hglrc)) == NULL)
                {
                    MessageBox::Show("wglMakeCurrent Failed");
                    return 0;
                }


                return 1;
            }

            bool InitGL(GLvoid)                                     // All setup for opengl goes here
            {
                glShadeModel(GL_SMOOTH);                            // Enable smooth shading
                glClearColor(0.0f, 0.0f, 0.0f, 0.5f);               // Black background
                glClearDepth(1.0f);                                 // Depth buffer setup
                glEnable(GL_DEPTH_TEST);                            // Enables depth testing
                glDepthFunc(GL_LEQUAL);                             // The type of depth testing to do
                glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  // Really nice perspective calculations
                return TRUE;                                        // Initialisation went ok
            }

            GLvoid ReSizeGLScene(GLsizei width, GLsizei height)     // Resize and initialise the gl window
            {
                if (height==0)                                      // Prevent A Divide By Zero By
                {
                    height=1;                                       // Making Height Equal One
                }

                glViewport(0,0,width,height);                       // Reset The Current Viewport

                glMatrixMode(GL_PROJECTION);                        // Select The Projection Matrix
                glLoadIdentity();                                   // Reset The Projection Matrix

                // Calculate The Aspect Ratio Of The Window
                gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

                glMatrixMode(GL_MODELVIEW);                         // Select The Modelview Matrix
                glLoadIdentity();                                   // Reset The Modelview Matrix
            }
            System::Void detectBlack(){


            }
        };
    }

第一个表单仅包含一个用于打开第二个表单的按钮

private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
            Form1^ freaker = gcnew Form1();
            freaker->ShowDialog();
             }

这是第二种形式的代码:

private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
         }
void Form1_Closing( Object^ /*sender*/, System::ComponentModel::CancelEventArgs^ e )
{
    this->OpenGL->~COpenGL();
}
//Time tick for play button option
private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e){
         UNREFERENCED_PARAMETER(sender);
         UNREFERENCED_PARAMETER(e);
         OpenGL->Render();
         OpenGL->SwapOpenGLBuffers();
     }

经过一周的搜索和尝试,答案是:

我在 Windows (wgl) 中找到了一个 class 来销毁 openGL 对象。仅此 class 并没有解决问题。我不得不调用所有命令,然后通过调用 SwapBuffers(m_hDC); 切换缓冲区并再次调用所有命令。后来我认识到只要调用命令g_hDC=NULL;g_hWnd=NULL;就足够了。这就是我的析构函数现在的样子:

~COpenGL(System::Void){


            if (g_bFullscreen)                                                                              // Are We In Fullscreen Mode?
            {
                    ChangeDisplaySettings(NULL,0);                                  // If So Switch Back To The Desktop
                    ShowCursor(TRUE);                                                               // Show Mouse Pointer
            }

            if (g_hRC)                                                                                      // Do We Have A Rendering Context?
            {
                    if (!wglMakeCurrent(NULL,NULL))                                 // Are We Able To Release The DC And RC Contexts?
                    {
                            MessageBox(NULL,TEXT("Release Of DC And RC Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
                    }

                    if (!wglDeleteContext(g_hRC))                                           // Are We Able To Delete The RC?
                    {
                            MessageBox(NULL,TEXT("Release Rendering Context Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
                    }
                    g_hRC=NULL;                                                                             // Set RC To NULL
            }

            if (g_hDC && !ReleaseDC(g_hWnd,g_hDC))                                  // Are We Able To Release The DC
            {
                    MessageBox(NULL,TEXT("Release Device Context Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
                    g_hDC=NULL;                                                                             // Set DC To NULL
            }

            if (g_hWnd && !DestroyWindow(g_hWnd))                                   // Are We Able To Destroy The Window?
            {
                    MessageBox(NULL,TEXT("Could Not Release hWnd."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
                    g_hWnd=NULL;                                                                            // Set hWnd To NULL
            }

            if (!UnregisterClass(TEXT("OpenGL"),g_hInstance))                       // Are We Able To Unregister Class
            {
                    MessageBox(NULL,TEXT("Could Not Unregister Class."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
                    g_hInstance=NULL;                                                                       // Set hInstance To NULL
            }



            SwapBuffers(g_hDC);

            g_hDC=NULL;
            g_hWnd=NULL; 

}