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;
}
我使用 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;
}