GtkGLArea 清除背景但不绘制

Posted

技术标签:

【中文标题】GtkGLArea 清除背景但不绘制【英文标题】:GtkGLArea clears background but does not draw 【发布时间】:2017-01-16 00:50:11 【问题描述】:

我一直在编写一个简单的 GTK+ 应用程序,并且刚刚开始进行图形开发。我知道这可能不是一个好的开始,直接跳入 3D 渲染,但我之前已经完成了少量工作,并且使用 Glade 并阅读了大量文档并取得了巨大成功,我认为这并不难整合两者 - 我想错了。手头的问题是glDrawArrays 似乎不起作用。我看了this question,不幸的是,它对我没有帮助。我再次关注了一些this tutorial on OpenGL 和this tutorial on GtkGLArea,但无济于事。

谁能指出我在这个问题上的正确方向?我不知道从这里去哪里。

相关代码如下:

#include "RenderingManager.hpp"

RenderingManager::RenderingManager()  
  ///GTK+ Setup///
  std::cout << "starting render constructor" << std::endl;
  glArea = GTK_GL_AREA(gtk_gl_area_new());
  std::cout << "got new glarea" << std::endl;
  g_signal_connect(GTK_WIDGET(glArea), "render", G_CALLBACK(signal_render), this);
  g_signal_connect(GTK_WIDGET(glArea), "realize", G_CALLBACK(signal_realize), this);
  g_signal_connect(GTK_WIDGET(glArea), "unrealize", G_CALLBACK(signal_unrealize), this);
  gtk_widget_show(GTK_WIDGET(glArea));
  ///Get Shaders///
  // vshader.open("vertex.shader");
  // fshader.open("fragment.shader");

  std::cout << "finished render constructor" << std::endl;


void RenderingManager::onRender() 
    // Dark blue background
    glClearColor(0.1f, 0.0f, 0.1f, 0.0f);
    draw_triangle();
    glFlush();

void RenderingManager::initBuffers () 
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

  glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);



void RenderingManager::loadShaders()  
  // Read the Vertex Shader code from the file
    std::ifstream VertexShaderStream("vertex.shader", std::ios::in);
    if(VertexShaderStream.is_open())
        std::string Line = "";
        while(getline(VertexShaderStream, Line))
            vshader += "\n" + Line;
        VertexShaderStream.close();
    

    // Read the Fragment Shader code from the file
    std::ifstream FragmentShaderStream("fragment.shader", std::ios::in);
    if(FragmentShaderStream.is_open())
        std::string Line = "";
        while(getline(FragmentShaderStream, Line))
            fshader += "\n" + Line;
        FragmentShaderStream.close();
    

  GLuint vsh, fsh;
  vsh = glCreateShader(GL_VERTEX_SHADER);
  fsh = glCreateShader(GL_FRAGMENT_SHADER);
  vshp = vshader.data();
  fshp = fshader.data();
  // vshp = vshader.get().c_str();
  // fshp = fshader.get().c_str();
  // vshader.get(vshp);
  // fshader.get(fshp);
  printf("%s\n%s\n", vshp, fshp);
  glShaderSource(vsh, 1, &vshp, NULL);
  glShaderSource(fsh, 1, &fshp, NULL);

  glCompileShader(vsh);
  glCompileShader(fsh);

  shaderProgramID = glCreateProgram();
  glAttachShader(shaderProgramID, vsh);
  glAttachShader(shaderProgramID, fsh);
  glLinkProgram(shaderProgramID);

  GLint Result = GL_FALSE;
  int InfoLogLength;
  // Check Vertex Shader
    glGetShaderiv(vsh, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(vsh, GL_INFO_LOG_LENGTH, &InfoLogLength);
    if ( InfoLogLength > 0 )
        char* VertexShaderErrorMessage = new char[InfoLogLength+1];
        glGetShaderInfoLog(vsh, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
        printf("%s\n", &VertexShaderErrorMessage[0]);
    
  // Check Fragment Shader
    glGetShaderiv(fsh, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(fsh, GL_INFO_LOG_LENGTH, &InfoLogLength);
    if ( InfoLogLength > 0 )
        char* FragmentShaderErrorMessage = new char[InfoLogLength+1];
        glGetShaderInfoLog(fsh, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
        printf("%s\n", &FragmentShaderErrorMessage[0]);
    

void RenderingManager::onActivate() 

  // We need to make the context current if we want to
  // call GL API
  gtk_gl_area_make_current (glArea);

  glewExperimental = GL_TRUE;
  glewInit();

  loadShaders();
  initBuffers();


void RenderingManager::signal_render(GtkGLArea *a, gpointer *user_data) 
  reinterpret_cast<RenderingManager*>(user_data)->onRender();


void RenderingManager::signal_realize(GtkGLArea *a, gpointer *user_data)  
  reinterpret_cast<RenderingManager*>(user_data)->onActivate();


void RenderingManager::signal_unrealize(GtkGLArea *a, gpointer *user_data)  
    //Don't do this
    //reinterpret_cast<RenderingManager*>(user_data)->~RenderingManager();

void RenderingManager::draw_triangle()  
  // Clear the screen
        glClear( GL_COLOR_BUFFER_BIT );

        // Use our shader
        glUseProgram(shaderProgramID);

        // 1rst attribute buffer : vertices
        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glVertexAttribPointer(
            0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
            3,                  // size
            GL_FLOAT,           // type
            GL_FALSE,           // normalized?
            0,                  // stride
            (void*)0            // array buffer offset
        );

        // Draw the triangle !
        glDrawArrays(GL_TRIANGLES, 0, 3); // 3 indices starting at 0 -> 1 triangle

        glDisableVertexAttribArray(0);


GtkGLArea *RenderingManager::expose()  
  //yikes
  return glArea;


RenderingManager::~RenderingManager() 
  glDeleteBuffers(1, &vbo);
    glDeleteVertexArrays(1, &vao);
    glDeleteProgram(shaderProgramID);
  std::cout << "GL Resources deleted." << std::endl;

【问题讨论】:

对于唯一的 reinterpret_cast "haxx" 来说,有一个你没有标记为 "haxx" 的值——直接调用你自己的析构函数。我很惊讶这在 C++ 中甚至是合法的。无论如何,即使你让它更理智(delete reinterpret_cast&lt;...&gt;(...)),这确实意味着一旦你没有意识到,你将永远不会再次被安全地意识到。考虑重组这些处理程序... @andlabs 可以,我不知道。 【参考方案1】:

由于 X11 的异步特性(Gtk+ 使用它),在窗口实现之前无法创建 gl-context(与 X11 建立连接)。

在你的 signal_realize() 中创建 gl-context 并在绘制之前使其成为当前状态,这应该在处理信号 expose_event (gtk+ 2) 或 draw(gtk+ 3) 时完成

【讨论】:

我不确定你的意思是什么——我认为这已经发生了。 onActivate 处理realize 信号,onRender 处理render 信号。如何创建 GL 上下文?如果我正确阅读了文档,我认为 GtkGLArea 会为我做到这一点...... 看这里的实现示例:developer.gnome.org/gtk3/unstable/… @TingPing 当我开始的时候我遵循了那个。我的代码包括所有这些元素,并且我已经填写了加载着色器和缓冲区等。不幸的是,我仍然卡住了。

以上是关于GtkGLArea 清除背景但不绘制的主要内容,如果未能解决你的问题,请参考以下文章

room-views-用窗口颜色清除背景(Clear Background with Window Colour)选项

在.Net中清除位图

为剪辑区域设置动画时清除画布时出现问题

尝试绘制波形但不绘制任何数据

在 UIView 中绘制文本然后清除它然后在不同的地方再次绘制

如何使用 CGContext 方法清除旧数据的绘制?