多个过剩窗口,但显示功能相同

Posted

技术标签:

【中文标题】多个过剩窗口,但显示功能相同【英文标题】:multiple glut windows but same display function 【发布时间】:2012-11-30 19:08:15 【问题描述】:

我正在尝试在过剩的两个窗口中渲染模型。但它仅在其中一个窗口中呈现。是否可以在具有不同回调函数的两个窗口中进行渲染?

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#define WINDOW_TITLE_PREFIX "Chapter 2"

int CurrentWidth = 800,
    CurrentHeight = 600,
    WindowHandle = 0;

unsigned FrameCount = 0;

GLuint
    VertexShaderId,
    FragmentShaderId,
    ProgramId,
    VaoId,
    VboId,
    ColorBufferId;

const GLchar* VertexShader =

    "#version 400\n"\

    "layout(location=0) in vec4 in_Position;\n"\
    "layout(location=1) in vec4 in_Color;\n"\
    "out vec4 ex_Color;\n"\

    "void main(void)\n"\
    "\n"\
    "   gl_Position = in_Position;\n"\
    "   ex_Color = in_Color;\n"\
    "\n"
;

const GLchar* FragmentShader =

    "#version 400\n"\

    "in vec4 ex_Color;\n"\
    "out vec4 out_Color;\n"\

    "void main(void)\n"\
    "\n"\
    "   out_Color = ex_Color;\n"\
    "\n"
;

void Initialize(int, char*[]);
void InitWindow(int, char*[]);
void ResizeFunction(int, int);
void ResizeFunction1(int, int);
void RenderFunction(void);
void RenderFunction1(void);
void TimerFunction(int);
void TimerFunction1(int);
void IdleFunction(void);
void IdleFunction1(void);
void Cleanup(void);
void CreateVBO(void);
void DestroyVBO(void);
void CreateShaders(void);
void DestroyShaders(void);

int Wh1;

int main(int argc, char* argv[])

    Initialize(argc, argv);

    glutMainLoop();

    exit(EXIT_SUCCESS);


void Initialize(int argc, char* argv[])

    GLenum GlewInitResult;

    InitWindow(argc, argv);

    glewExperimental = GL_TRUE;
    GlewInitResult = glewInit();

    if (GLEW_OK != GlewInitResult) 
        fprintf(
            stderr,
            "ERROR: %s\n",
            glewGetErrorString(GlewInitResult)
        );
        exit(EXIT_FAILURE);
    

    fprintf(
        stdout,
        "INFO: OpenGL Version: %s\n",
        glGetString(GL_VERSION)
    );

    CreateShaders();
    CreateVBO();

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);


void InitWindow(int argc, char* argv[])

    glutInit(&argc, argv);

    glutInitContextVersion(4, 0);
    glutInitContextFlags(GLUT_FORWARD_COMPATIBLE);
    glutInitContextProfile(GLUT_CORE_PROFILE);

    glutSetOption(
        GLUT_ACTION_ON_WINDOW_CLOSE,
        GLUT_ACTION_GLUTMAINLOOP_RETURNS
    );

    glutInitWindowSize(CurrentWidth, CurrentHeight);

    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);

    WindowHandle = glutCreateWindow(WINDOW_TITLE_PREFIX);
    std::cout<<WindowHandle<<std::endl;
    if(WindowHandle < 1) 
        fprintf(
            stderr,
            "ERROR: Could not create a new rendering window.\n"
        );
        exit(EXIT_FAILURE);
    
    glutSetWindow(WindowHandle);
    glutReshapeFunc(ResizeFunction);
    glutDisplayFunc(RenderFunction);
    glutTimerFunc(0, TimerFunction, 0);
    glutCloseFunc(Cleanup);
#if 1
    Wh1 = glutCreateWindow("sasd"); 
//  std::cout<<i<<"s"<<std::endl;
    glutReshapeFunc(ResizeFunction1);
    glutDisplayFunc(RenderFunction1);
    glutTimerFunc(0, TimerFunction1, 0);
    glutCloseFunc(Cleanup);
    glutSetWindow(Wh1);
#endif



void ResizeFunction(int Width, int Height)

    CurrentWidth = Width;
    CurrentHeight = Height;
    glViewport(0, 0, CurrentWidth, CurrentHeight);



void ResizeFunction1(int Width, int Height)

    CurrentWidth = Width;
    CurrentHeight = Height;
    glViewport(0, 0, CurrentWidth, CurrentHeight);


void RenderFunction(void)

    ++FrameCount;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glDrawArrays(GL_TRIANGLES, 0, 3);

    glutSwapBuffers();
    glutSetWindow(WindowHandle);
    glutPostRedisplay();
    glutSetWindow(Wh1);
    glutPostRedisplay();


void RenderFunction1(void)

    ++FrameCount;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glDrawArrays(GL_TRIANGLES, 0, 3);

    glutSwapBuffers();

    glutSetWindow(WindowHandle);
    glutPostRedisplay();
    glutSetWindow(Wh1);
    glutPostRedisplay();


void IdleFunction(void)

    glutSetWindow(WindowHandle);
    glutPostRedisplay();
    glutSetWindow(Wh1);
    glutPostRedisplay();


void IdleFunction1(void)

    glutSetWindow(WindowHandle);
    glutPostRedisplay();
    glutSetWindow(Wh1);
    glutPostRedisplay();

void TimerFunction(int Value)

    if (0 != Value) 
        char* TempString = (char*)
            malloc(512 + strlen(WINDOW_TITLE_PREFIX));

        sprintf(
            TempString,
            "%s: %d Frames Per Second @ %d x %d",
            WINDOW_TITLE_PREFIX,
            FrameCount * 4,
            CurrentWidth,
            CurrentHeight
        );

        //glutSetWindowTitle(TempString);
        free(TempString);
    

    FrameCount = 0;
    glutTimerFunc(250, TimerFunction, 1);

void TimerFunction1(int Value)

    if (0 != Value) 
        char* TempString = (char*)
            malloc(512 + strlen(WINDOW_TITLE_PREFIX));

        sprintf(
            TempString,
            "%s: %d Frames Per Second @ %d x %d",
            WINDOW_TITLE_PREFIX,
            FrameCount * 4,
            CurrentWidth,
            CurrentHeight
        );

        //glutSetWindowTitle(TempString);
        free(TempString);
    

    FrameCount = 0;
    glutTimerFunc(250, TimerFunction, 1);


void Cleanup(void)

    DestroyShaders();
    DestroyVBO();


void CreateVBO(void)

    GLfloat Vertices[] = 
        -0.8f, -0.8f, 0.0f, 1.0f,
         0.0f,  0.8f, 0.0f, 1.0f,
         0.8f, -0.8f, 0.0f, 1.0f
    ;

    GLfloat Colors[] = 
        1.0f, 0.0f, 0.0f, 1.0f,
        0.0f, 1.0f, 0.0f, 1.0f,
        0.0f, 0.0f, 1.0f, 1.0f
    ;

    GLenum ErrorCheckValue = glGetError();

    glGenVertexArrays(1, &VaoId);
    glBindVertexArray(VaoId);

    glGenBuffers(1, &VboId);
    glBindBuffer(GL_ARRAY_BUFFER, VboId);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(0);

    glGenBuffers(1, &ColorBufferId);
    glBindBuffer(GL_ARRAY_BUFFER, ColorBufferId);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Colors), Colors, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(1);

    ErrorCheckValue = glGetError();
    if (ErrorCheckValue != GL_NO_ERROR)
    
        fprintf(
            stderr,
            "ERROR: Could not create a VBO: %s \n",
            gluErrorString(ErrorCheckValue)
        );

        exit(-1);
    


void DestroyVBO(void)

    GLenum ErrorCheckValue = glGetError();

    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glDeleteBuffers(1, &ColorBufferId);
    glDeleteBuffers(1, &VboId);

    glBindVertexArray(0);
    glDeleteVertexArrays(1, &VaoId);

    ErrorCheckValue = glGetError();
    if (ErrorCheckValue != GL_NO_ERROR)
    
        fprintf(
            stderr,
            "ERROR: Could not destroy the VBO: %s \n",
            gluErrorString(ErrorCheckValue)
        );

        exit(-1);
    


void CreateShaders(void)

    GLenum ErrorCheckValue = glGetError();

    VertexShaderId = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(VertexShaderId, 1, &VertexShader, NULL);
    glCompileShader(VertexShaderId);

    FragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(FragmentShaderId, 1, &FragmentShader, NULL);
    glCompileShader(FragmentShaderId);

    ProgramId = glCreateProgram();
        glAttachShader(ProgramId, VertexShaderId);
        glAttachShader(ProgramId, FragmentShaderId);
    glLinkProgram(ProgramId);
    glUseProgram(ProgramId);

    ErrorCheckValue = glGetError();
    if (ErrorCheckValue != GL_NO_ERROR)
    
        fprintf(
            stderr,
            "ERROR: Could not create the shaders: %s \n",
            gluErrorString(ErrorCheckValue)
        );

        exit(-1);
    


void DestroyShaders(void)

    GLenum ErrorCheckValue = glGetError();

    glUseProgram(0);

    glDetachShader(ProgramId, VertexShaderId);
    glDetachShader(ProgramId, FragmentShaderId);

    glDeleteShader(FragmentShaderId);
    glDeleteShader(VertexShaderId);

    glDeleteProgram(ProgramId);

    ErrorCheckValue = glGetError();
    if (ErrorCheckValue != GL_NO_ERROR)
    
        fprintf(
            stderr,
            "ERROR: Could not destroy the shaders: %s \n",
            gluErrorString(ErrorCheckValue)
        );

        exit(-1);
    

【问题讨论】:

【参考方案1】:

glutDisplayFunc 和所有其他回调为调用函数时当前的任何窗口设置回调。所以如果你想为某个窗口设置显示回调,在调用glutSetWindow之后再调用glutDisplayFunc

我发现了 gldrawArrays 需要创建新的 vbo 来重绘的问题。我不知道为什么。

这是因为每个窗口都代表一个独立的 OpenGL 上下文。除非您显式共享对象(通过特定于平台的调用),否则每个上下文都会有自己的独立对象。如果没有明确共享(并且在新上下文中创建对象之前这样做),您不能使用在另一个中创建的缓冲区。

【讨论】:

man glutDisplayFunc: "glutDisplayFunc 设置当前窗口的显示回调。";顺便说一句,我没有投反对票。 但是一旦你创建了一个新窗口。新窗口成为当前窗口。我发现了 gldrawArrays 需要创建新的 vbo 来重绘的问题。我不知道为什么。如果我在 gldrawarrays 函数之前在 display 函数中调用 createVBO,则会显示三角形,但旧窗口中的颜色信息会丢失。 (好奇怪)。 我认为问题可能是 gldrawArrays 不是线程安全的。 glut 中的两个窗口可以作为 glut 库中的线程实现..【参考方案2】:

Opengl 函数不是线程安全的。因此,多个窗口中的 gldrawArrays 可能在两个线程中运行。所以他们的行为是不确定的。

【讨论】:

FreeGLUT 不会创建不同的线程。所有窗口都由同一个线程处理。 是的。你说的对。我试图通过在函数的开始和结束处放置信号量锁和解锁来使显示函数原子化。没有变化..

以上是关于多个过剩窗口,但显示功能相同的主要内容,如果未能解决你的问题,请参考以下文章

在 Presto 中为多个功能重复相同的窗口?

在多个组件中触发相同的功能

把若干张抬头相同的EXECL表格如何合并在一起?

Opencv - 如何使用与多个线程共享的 imshow() 方法相同的窗口

如何在谷歌地图上显示多个信息窗口?

过剩鼠标坐标