控制台菜单更新 OpenGL 窗口
Posted
技术标签:
【中文标题】控制台菜单更新 OpenGL 窗口【英文标题】:Console menu updating OpenGL window 【发布时间】:2009-02-08 05:46:54 【问题描述】:我正在制作一个执行一些自定义图像处理的应用程序。该程序将由控制台中的一个简单菜单驱动。用户将输入图像的文件名,该图像将使用 openGL 在窗口中显示。当用户选择对图像进行一些处理时,处理完成,openGL窗口应该重新绘制图像。
我的问题是我的图像从未被绘制到窗口上,而是窗口始终是黑色的。我认为这可能与我在程序中组织线程的方式有关。主执行线程处理菜单输入/输出和图像处理并调用 Display 方法,而第二个线程运行 openGL 主循环。
这是我的主要代码:
#include <iostream>
#include <GL/glut.h>
#include "ImageProcessor.h"
#include "BitmapImage.h"
using namespace std;
DWORD WINAPI openglThread( LPVOID param );
void InitGL();
void Reshape( GLint newWidth, GLint newHeight );
void Display( void );
BitmapImage* b;
ImageProcessor ip;
int main( int argc, char *argv[] )
DWORD threadID;
b = new BitmapImage();
CreateThread( 0, 0, openglThread, NULL, 0, &threadID );
while( true )
char choice;
string path = "TestImages\\";
string filename;
cout << "Enter filename: ";
cin >> filename;
path += filename;
b = new BitmapImage( path );
Display();
cout << "1) Invert" << endl;
cout << "2) Line Thin" << endl;
cout << "Enter choice: ";
cin >> choice;
if( choice == '1' )
ip.InvertColour( *b );
else
ip.LineThinning( *b );
Display();
return 0;
void InitGL()
int argc = 1;
char* argv[1];
argv[0] = new char[20];
strcpy( argv[0], "main" );
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition( 0, 0 );
glutInitWindowSize( 800, 600 );
glutCreateWindow( "ICIP Program - Character recognition using line thinning, Hilbert curve, and wavelet approximation" );
glutDisplayFunc( Display );
glutReshapeFunc( Reshape );
glClearColor(0.0,0.0,0.0,1.0);
glEnable(GL_DEPTH_TEST);
void Reshape( GLint newWidth, GLint newHeight )
/* Reset viewport and projection parameters */
glViewport( 0, 0, newWidth, newHeight );
void Display( void )
glClear (GL_COLOR_BUFFER_BIT); // Clear display window.
b->Draw();
glutSwapBuffers();
DWORD WINAPI openglThread( LPVOID param )
InitGL();
glutMainLoop();
return 0;
这是我的 BitmapImage 绘制方法:
void BitmapImage::Draw()
cout << "Drawing" << endl;
if( _loaded )
glBegin( GL_POINTS );
for( unsigned int i = 0; i < _height * _width; i++ )
glColor3f( _bitmap_image[i*3] / 255.0, _bitmap_image[i*3+1] / 255.0, _bitmap_image[i*3+2] / 255.0 );
// invert the y-axis while drawing
glVertex2i( i % _width, _height - (i / _width) );
glEnd();
对这个问题有什么想法吗?
编辑:通过从每 500 毫秒调用 glutPostRedisplay() 的 openglThread 启动一个 glutTimer 从技术上解决了这个问题。现在这没问题,但我更喜欢这样一种解决方案,在这种解决方案中,每次我对位图进行更改时我只需要重新显示(以节省处理时间),并且我不必运行另一个线程(计时器是我假设的另一个线程)。这主要是因为主处理线程将做大量密集的工作,我想将大部分资源专用于该线程而不是其他任何东西。
【问题讨论】:
投票结束,为什么这段代码不起作用。 【参考方案1】:我以前也遇到过这个问题 - 这很烦人。问题是您的所有 OpenGL 调用都必须在您启动 OpenGL 上下文的线程中完成。因此,当您希望您的主(输入)线程更改 OpenGL 线程中的某些内容时,您需要以某种方式向线程发出信号,告知它需要执行某些操作(设置标志或其他内容)。
注意:我不知道你的 BitmapImage
加载函数(这里是你的构造函数)做了什么,但它可能有一些 OpenGL 调用。以上也适用!因此,您需要向其他线程发出信号,为您创建一个BitmapImage
,或者至少在创建位图时执行与 OpenGL 相关的部分。
【讨论】:
这并不完全准确,要求 OpenGL 上下文只能是当前到任何单个线程。然而,上下文可以在与其当前所在的线程不同的线程中创建。例如,这对于屏幕外渲染很有用。 澄清一下,这种情况下的问题肯定是多线程渲染,因为 OP 使用相同的上下文从不同的线程进行 gl 调用,或者更确切地说是不存在的上下文(在主线程)。 重新评论 #1,这是真的,但我认为这与这个特定示例无关(并且是不必要的复杂化)。【参考方案2】:几点:
1234563在你的情况下,我建议将密集的图像处理任务转移到一个线程中,并在你的主线程中进行 OpenGL 渲染。为了绘制图像,您使用的是顶点而不是带纹理的四边形。除非您有充分的理由,否则使用单个带纹理的四边形(处理后的图像即纹理)会快得多。查看glTexImage2D 和glTexSubImage2D。
如果您使用加速的 OpenGL 实现(在任何现代系统上几乎可以保证)并且如果您使用带纹理的四边形,而不是每个像素的顶点。
【讨论】:
【参考方案3】:你的问题可能出在 Display() 行
b->画图();
我没有看到 b 在哪里传递到 Display() 的范围内。
【讨论】:
b 在 main() 上方全局声明 是的,我现在在晨光中看到它。【参考方案4】:您需要在创建上下文的线程上进行 OpenGL 调用 (glutInitDisplayMode)。因此,将不会定义位于不同线程上的 Display 方法内部的 glXX 调用。您可以通过转储函数地址轻松看到这一点,希望它是未定义的或 NULL。
【讨论】:
【参考方案5】:听起来 500 毫秒计时器定期调用 Display(),在 2 次调用后,它以相同的渲染填充后缓冲区和前缓冲区。 Display() 会继续被调用,直到用户输入了一些 OpenGL 线程永远不知道的内容,但是由于全局变量 b 现在不同,线程在 Display() 中盲目地使用它。
那么如何按照 Jesse Beder 所说的那样使用全局 int(称为标志)来标记用户输入内容的时间。例如:
设置标志 = 1;在你做 b = new BitmapImage( path );
然后设置标志 = 0;从 OpenGL 线程调用 Display() 之后。
你在计时器上循环,但是,现在检查 flag = 1。你只需要在 flag = 1 时调用 glutPostRedisplay(),即用户输入了一些东西。
似乎是不使用睡眠/唤醒机制的好方法。在多个线程之间访问全局变量也可能是不安全的。我认为这里可能发生的最坏情况是 OpenGL 线程未读标志 = 0,而它应该读取标志 = 1。然后它应该在不超过几次迭代后捕获它。如果你有奇怪的行为去同步。
使用您显示的代码,您在 main() 中调用了两次 Display()。其实main()甚至不需要调用Display(),OpenGL线程就可以了。
【讨论】:
以上是关于控制台菜单更新 OpenGL 窗口的主要内容,如果未能解决你的问题,请参考以下文章