c - C 中的 Gtk GLArea 小部件不显示 gl 命令

标签 c opengl gtk gobject gdk

我之前曾问过一个关于尝试在 PyGObject 中使用 GLArea 小部件的问题 ( Use of the Gtk.GLArea in Pygobject GTK3 )。我从来没有得到过 python 版本来绘制命令,所以我想我应该尝试一下 c 版本来更好地理解它。使用 Ubuntu 16,因为 Gtk3 已全部包含在内,我尝试了一下。以下代码编译并运行时不会出现错误或警告,但不会绘制包含的 GL_LINES 指令。真正奇怪的是改变 glClearColor 确实改变了背景,并且 GL_LINES 在同一个函数中。正如你所看到的,我正在使用 Ubuntu 包含的 Epoxy/gl 库,我相信它相当于 GL/gl。有什么想法吗?

/*to compile -> 
gcc `pkg-config --cflags gtk+-3.0` -o gl_area gl_area.c `pkg-config --libs gtk+-3.0 epoxy`*/
#include <math.h>
#include <gtk/gtk.h>
#include <epoxy/gl.h>
#include <stdio.h>


gint init(GtkWidget *widget)
{
  /* Setup the viewport*/
      glViewport(0, 0,  gtk_widget_get_allocated_width (widget),
                        gtk_widget_get_allocated_height(widget));
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glOrtho(0,100, 100,0, -1,1);
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();

      printf("ran init method\n");
      return TRUE;
}



/* When widget is exposed it's contents are redrawn. */
static gboolean
render (GtkGLArea *area, GdkGLContext *context)
{
  /* OpenGL functions can be called only if make_current returns true */

      /* Draw simple triangle */
      glClearColor(.3,.3,.3,1);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      glColor4f(1,1,1,1);
      glBegin(GL_LINES);
{
      glVertex2f(0,0);
      glVertex2f(10000,10000);
      glVertex2f(0,0);
      glVertex2f(-10000,-10000);
      glVertex2f(0,0);
      glVertex2f(10000,-10000);
      glVertex2f(0,0);
      glVertex2f(-10000,10000);
}
      glEnd();
      printf("ran render method\n");
  return TRUE;
}

/* When glarea widget size changes, viewport size is set to match the new size */
gint reshape(GtkWidget *widget, GdkEventConfigure *event)
{
  /* OpenGL functions can be called if context is current */
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      printf("ran rehsape method\n");
    glViewport(0, 0, gtk_widget_get_allocated_width (widget),
                        gtk_widget_get_allocated_height(widget));
  return TRUE;
}


int main(int argc, char **argv)
{
/* initialize gtk */
gtk_init(&argc, &argv);

/* Create new top level window. */
GtkWidget *window = gtk_window_new( GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "GL Area Test");
gtk_window_set_default_size (GTK_WINDOW(window),
                             640,
                            480);
  gtk_container_set_border_width(GTK_CONTAINER(window), 10);

  /* Quit main if got delete event */
  g_signal_connect(G_OBJECT(window),
                    "delete-event",
                    G_CALLBACK(gtk_main_quit), 
                    NULL);

  /* Create new OpenGL widget. */
GtkWidget *glarea = gtk_gl_area_new ();

  /* Do initialization when widget has been realized. */
 g_signal_connect(glarea, "realize",  G_CALLBACK(init), NULL);
  /* When window is resized viewport needs to be resized also. */
 g_signal_connect(glarea, "configure-event",  G_CALLBACK(reshape), NULL);

  /* Render signal should be sent once the context is set to current. */
g_signal_connect (glarea, "render", G_CALLBACK (render), NULL);


  /* set minimum size */
 gtk_widget_set_size_request(glarea, 100,100);

  /* put glarea into window and show it all */
 gtk_container_add(GTK_CONTAINER(window), glarea);
 gtk_widget_show_all (window);
 gtk_main();
 return 0;
}

最佳答案

enter image description here好吧,我对 openGL 和着色器的使用有了更多的了解。基本上,GLArea 遇到的问题是命令不在“绑定(bind)”到当前上下文的事件缓冲区的数组中。这句话很有帮助:https://www.youtube.com/watch?v=Q_kFcRlLTk0我修改了演示代码以简化它,并将着色器源代码作为字符串放入 C 代码中。事实上,它将从演示应用程序打开,并具有 slider 以矩阵旋转三角形。我试图将其提炼为最基本的窗口。这确实编译并运行没有错误。现在我将在 PyGObject 中尝试一下。

/* OpenGL Area
 *
 * GtkGLArea is a widget that allows custom drawing using OpenGL calls.
 */
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <gtk/gtk.h>
#include <epoxy/gl.h>

const GLchar *FRAGMENT_SOURCE =
"#version 330\n"
"in vec4 inputColor;\n"
"out vec4 outputColor;\n"
"void main() {\n"
"outputColor = vec4(1.0f, 0.0f, 0.0f, 0.0f);\n" //constant red. I know it's a poor shader
"}";
const GLchar  *VERTEX_SOURCE =
"#version 330\n"
"in vec4 position;\n"
"void main()\n{gl_Position =  position;\n"
"}";


/* the GtkGLArea widget */
static GtkWidget *gl_area = NULL;

/* The object we are drawing */
static const GLfloat vertex_data[] = {
  0.f,   0.5f,   0.f, 1.f,
  0.5f, -0.366f, 0.f, 1.f,
 -0.5f, -0.366f, 0.f, 1.f,
};

/* Initialize the GL buffers */
static void
init_buffers (GLuint *vao_out,
              GLuint *buffer_out)
{
  GLuint vao, buffer;

  /* We only use one VAO, so we always keep it bound */
  glGenVertexArrays (1, &vao);
  glBindVertexArray (vao);

  /* This is the buffer that holds the vertices */
  glGenBuffers (1, &buffer);
  glBindBuffer (GL_ARRAY_BUFFER, buffer);
  glBufferData (GL_ARRAY_BUFFER, sizeof (vertex_data), vertex_data, GL_STATIC_DRAW);
  glBindBuffer (GL_ARRAY_BUFFER, 0);

  if (vao_out != NULL)
    *vao_out = vao;

  if (buffer_out != NULL)
    *buffer_out = buffer;
}

/* Create and compile a shader */
static GLuint
create_shader (int  type)
{
  GLuint shader;
  int status;
  shader = glCreateShader (type);
if (type== GL_FRAGMENT_SHADER){
  glShaderSource (shader, 1, &FRAGMENT_SOURCE, NULL);}
if (type== GL_VERTEX_SHADER){
  glShaderSource (shader, 1, &VERTEX_SOURCE, NULL);}
  glCompileShader (shader);

  glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
  if (status == GL_FALSE)
    {
      int log_len;
      char *buffer;
      glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &log_len);
      buffer = g_malloc (log_len + 1);
      glGetShaderInfoLog (shader, log_len, NULL, buffer);
      g_warning ("Compile failure in %s shader:\n%s",
                 type == GL_VERTEX_SHADER ? "vertex" : "fragment",
                 buffer);
      g_free (buffer);
      glDeleteShader (shader);
      return 0;
    }

  return shader;
}

/* Initialize the shaders and link them into a program */
static void
init_shaders (GLuint *program_out)
{
  GLuint vertex, fragment;
  GLuint program = 0;
  int status;
  vertex = create_shader (GL_VERTEX_SHADER);

  if (vertex == 0)
    {
      *program_out = 0;
      return;
    }

  fragment = create_shader (GL_FRAGMENT_SHADER);

  if (fragment == 0)
    {
      glDeleteShader (vertex);
      *program_out = 0;
      return;
    }

  program = glCreateProgram ();
  glAttachShader (program, vertex);
  glAttachShader (program, fragment);

  glLinkProgram (program);

  glGetProgramiv (program, GL_LINK_STATUS, &status);
  if (status == GL_FALSE)
    {
      int log_len;
      char *buffer;

      glGetProgramiv (program, GL_INFO_LOG_LENGTH, &log_len);

      buffer = g_malloc (log_len + 1);
      glGetProgramInfoLog (program, log_len, NULL, buffer);

      g_warning ("Linking failure:\n%s", buffer);

      g_free (buffer);

      glDeleteProgram (program);
      program = 0;

      goto out;
    }


  glDetachShader (program, vertex);
  glDetachShader (program, fragment);

out:
  glDeleteShader (vertex);
  glDeleteShader (fragment);

  if (program_out != NULL)
    *program_out = program;

}


static GLuint position_buffer;
static GLuint program;

/* We need to set up our state when we realize the GtkGLArea widget */
static void
realize (GtkWidget *widget)
{
  GdkGLContext *context;
  gtk_gl_area_make_current (GTK_GL_AREA (widget));
  if (gtk_gl_area_get_error (GTK_GL_AREA (widget)) != NULL)
    return;
  context = gtk_gl_area_get_context (GTK_GL_AREA (widget));
  init_buffers (&position_buffer, NULL);
  init_shaders (&program);
}

/* We should tear down the state when unrealizing */
static void
unrealize (GtkWidget *widget)
{
  gtk_gl_area_make_current (GTK_GL_AREA (widget));

  if (gtk_gl_area_get_error (GTK_GL_AREA (widget)) != NULL)
    return;

  glDeleteBuffers (1, &position_buffer);
  glDeleteProgram (program);
}

static void
draw_triangle (void)
{

  /* Use our shaders */
  glUseProgram (program);


  /* Use the vertices in our buffer */
  glBindBuffer (GL_ARRAY_BUFFER, position_buffer);
  glEnableVertexAttribArray (0);
  glVertexAttribPointer (0, 4, GL_FLOAT, GL_FALSE, 0, 0);
  /* Draw the three vertices as a triangle */
  glDrawArrays (GL_TRIANGLES, 0, 3);

  /* We finished using the buffers and program */
  glDisableVertexAttribArray (0);
  glBindBuffer (GL_ARRAY_BUFFER, 0);
  glUseProgram (0);
}

static gboolean
render (GtkGLArea    *area,
        GdkGLContext *context)
{
  if (gtk_gl_area_get_error (area) != NULL)
    return FALSE;

  /* Clear the viewport */
  glClearColor (0.0, 0.0, 0.0, 1.0);
  glClear (GL_COLOR_BUFFER_BIT);

  /* Draw our object */
  draw_triangle ();

  /* Flush the contents of the pipeline */
  glFlush ();

  return TRUE;
}

static void
on_axis_value_change (void)
{
  gtk_widget_queue_draw (gl_area);
}



int main(int argc, char **argv)
{
GtkWidget *window, *box;
/* initialize gtk */
gtk_init(&argc, &argv);
/* Create new top level window. */
window = gtk_window_new( GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size (GTK_WINDOW(window),1000,1000);
    gtk_window_set_title(GTK_WINDOW(window), "GL Area");
    gtk_container_set_border_width(GTK_CONTAINER(window), 10);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);
    g_object_set (box, "margin", 12, NULL);
    gtk_box_set_spacing (GTK_BOX (box), 6);
    gtk_container_add (GTK_CONTAINER (window), box);
gl_area = gtk_gl_area_new ();
    gtk_box_pack_start (GTK_BOX(box), gl_area,1,1, 0);
    /* We need to initialize and free GL resources, so we use
    * the realize and unrealize signals on the widget
    */
    g_signal_connect (gl_area, "realize", G_CALLBACK (realize), NULL);
    g_signal_connect (gl_area, "unrealize", G_CALLBACK (unrealize), NULL);

    /* The main "draw" call for GtkGLArea */
    g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL);
    /* Quit form main if got delete event */
    g_signal_connect(G_OBJECT(window), "delete-event",
                   G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_main();

  return 0;
}

关于c - C 中的 Gtk GLArea 小部件不显示 gl 命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47746674/

相关文章:

c - Ferror 是否会进行多次写入?

C:如果字符串内部存在子串,则将字符串中的小写字母改为大写字母

java - 正交投影 - 使物体适合屏幕?

c++ - Gtk+ GtkComboBox 插入 GtkWidget 而不是字符串

c - 为什么此C程序会产生意外的输出?

c - 如何使用 C 中的 ctime() 从套接字读取字节

c++ - 我正在努力理解着色器中的某些东西

c++ - Qt3d。在三角形上绘制透明的QSphereMesh

c - 从 GTK 条目中获取文本

python - pyGtk:图像阻止窗口调整大小