I'm experimenting with using the GtkGLArea
widget at the moment. None of the answers to similar questions seem to pertain to this situation.
glClear()
can set the background colour just fine but actually drawing arrays of triangles isn't.
According to this tutorial, the code below should work.
EDIT: 21/5/2015: Added shaders, still getting same results. New code below
Here's the main.c
and the SConstruct
so you can build with scons:
SOLVED: Working code under the heading SOLUTION: main.c the same SConstruct file can be used to build example
main.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include <gdk/gdkx.h>
#include <epoxy/glx.h>
#include <epoxy/gl.h>
#include <gtk/gtk.h>
#include <gtk/gtkglarea.h>
#define IGNORE_VAR(type, identifier) \
{ \
type IGNORED_VARIABLE_abcd = identifier; \
identifier = IGNORED_VARIABLE_abcd; \
}
const GLchar *vert_src ="\n" \
"#version 330 \n" \
" \n" \
"layout(location = 0) in vec2 in_position; \n" \
" \n" \
"void main() \n" \
"{ \n" \
" gl_Position = in_position; \n" \
"} \n";
const GLchar *frag_src ="\n" \
"void main (void) \n" \
"{ \n" \
" gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); \n" \
"} \n";
GLuint gl_buffer, gl_program;
static gboolean realise(GtkGLArea *area, GdkGLContext *context)
{
IGNORE_VAR(GdkGLContext*, context);
gtk_gl_area_make_current(GTK_GL_AREA(area));
if (gtk_gl_area_get_error (GTK_GL_AREA(area)) != NULL)
{
printf("Failed to initialiize buffers\n");
return FALSE;
}
GLfloat verts[] =
{
+0.0f, +1.0f,
-1.0f, -1.0f,
+1.0f, -1.0f,
};
GLuint frag_shader, vert_shader;
frag_shader = glCreateShader(GL_FRAGMENT_SHADER);
vert_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(frag_shader, 1, &frag_src, NULL);
glShaderSource(vert_shader, 1, &vert_src, NULL);
glCompileShader(frag_shader);
glCompileShader(vert_shader);
gl_program = glCreateProgram();
glAttachShader(gl_program, frag_shader);
glAttachShader(gl_program, vert_shader);
glLinkProgram(gl_program);
glGenBuffers(1, &gl_buffer);
glBindBuffer(GL_ARRAY_BUFFER, gl_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
return TRUE;
}
static gboolean render(GtkGLArea *area, GdkGLContext *context)
{
IGNORE_VAR(GdkGLContext*, context);
IGNORE_VAR(GtkGLArea*, area);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindBuffer(GL_ARRAY_BUFFER, gl_buffer);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
//glUseProgram(gl_program);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
return TRUE;
}
int main(int argc, char** argv)
{
gtk_init(&argc, &argv);
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL),
*gl_area = gtk_gl_area_new();
g_signal_connect(window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(gl_area, "realize", G_CALLBACK(realise), NULL);
g_signal_connect(gl_area, "render", G_CALLBACK(render), NULL);
gtk_container_add(GTK_CONTAINER(window), gl_area);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Sconstruct
import os
env = Environment(CC='gcc', CCFLAGS='--std=c11', ENV={'PATH':os.environ['PATH']})
env.Append(LIBS = ['GL', 'epoxy'])
env.ParseConfig('pkg-config --cflags --libs gtk+-3.0')
#env.ParseConfig('pkg-config --cflags gdkglext-1.0')
env.Program(target='gl', source=['main.c'])
# vim: set filetype=python:
SOLUTION: main.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include <gdk/gdkx.h>
#include <epoxy/glx.h>
#include <epoxy/gl.h>
#include <gtk/gtk.h>
#define IGNORE_VAR(type, identifier) \
{ \
type IGNORED_VARIABLE_abcd = identifier; \
identifier = IGNORED_VARIABLE_abcd; \
}
const GLchar *vert_src ="\n" \
"#version 330 \n" \
"#extension GL_ARB_explicit_attrib_location: enable \n" \
" \n" \
"layout(location = 0) in vec2 in_position; \n" \
" \n" \
"void main() \n" \
"{ \n" \
" gl_Position = vec4(in_position, 0.0, 1.0); \n" \
"} \n";
const GLchar *frag_src ="\n" \
"void main (void) \n" \
"{ \n" \
" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); \n" \
"} \n";
GLuint gl_vao, gl_buffer, gl_program;
static gboolean realise(GtkGLArea *area, GdkGLContext *context)
{
IGNORE_VAR(GdkGLContext*, context);
gtk_gl_area_make_current(GTK_GL_AREA(area));
if (gtk_gl_area_get_error (GTK_GL_AREA(area)) != NULL)
{
printf("Failed to initialiize buffers\n");
return FALSE;
}
GLfloat verts[] =
{
+0.0f, +1.0f,
-1.0f, -1.0f,
+1.0f, -1.0f,
};
GLuint frag_shader, vert_shader;
frag_shader = glCreateShader(GL_FRAGMENT_SHADER);
vert_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(frag_shader, 1, &frag_src, NULL);
glShaderSource(vert_shader, 1, &vert_src, NULL);
glCompileShader(frag_shader);
glCompileShader(vert_shader);
gl_program = glCreateProgram();
glAttachShader(gl_program, frag_shader);
glAttachShader(gl_program, vert_shader);
glLinkProgram(gl_program);
glGenVertexArrays(1, &gl_vao);
glBindVertexArray(gl_vao);
glGenBuffers(1, &gl_buffer);
glBindBuffer(GL_ARRAY_BUFFER, gl_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindVertexArray(0);
glDeleteBuffers(1, &gl_buffer);
return TRUE;
}
static gboolean render(GtkGLArea *area, GdkGLContext *context)
{
IGNORE_VAR(GdkGLContext*, context);
IGNORE_VAR(GtkGLArea*, area);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0, 0.0, 0.0, 1.0);
glUseProgram(gl_program);
glBindVertexArray(gl_vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray (0);
glUseProgram (0);
glFlush();
return TRUE;
}
int main(int argc, char** argv)
{
gtk_init(&argc, &argv);
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL),
*gl_area = gtk_gl_area_new();
g_signal_connect(window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(gl_area, "realize", G_CALLBACK(realise), NULL);
g_signal_connect(gl_area, "render", G_CALLBACK(render), NULL);
gtk_container_add(GTK_CONTAINER(window), gl_area);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
You're using generic vertex attributes. As such you're supposed to use shaders. If you're in a compatibility profile your use of vertex attribute 0 may be interpreted as built-in attribute "vertex position", but that's not a given. So if you want to operate "by the book" you must supply a shader (or stick with the deprecated built-in attributes).
On a side note: Enabling the vertex attribute array and setting the pointer in the initialization code is not recommendable. Anything may happen with the OpenGL context between those two, including binding other vertex arrays, disabling/enabling (other) vertex attribute arrays, setting different buffer pointers, etc.
As a rule of thumb, anything that's directly related to drawing state (i.e. that does not constitute one time data initialization/loading) belongs at the corresponding place of the drawing code. In your case
static gboolean render(GtkGLArea *area, GdkGLContext *context)
{
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glFrontFace(GL_CW);
/* added these ---> */
glBindBuffer(GL_ARRAY_BUFFER, gl_buffer);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
/* <--- */
glDrawArrays(GL_TRIANGLES, 0, 3);
//gtk_widget_get_realized(area);
return TRUE;
}
Doing not so will create will confuse you in the long run.
You don't appear to have any shaders. You need a fragment and vertex shader.
Here's a tutorial on how to write and use them: https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/loading.php
You are missing the creation of the VAO; GTK+ will create GL core profile contexts, which means you need to create and select the VAO yourself, otherwise your vertex buffer objects won't be used.
When initializing the GL state, add this:
/* we need to create a VAO to store the other buffers */
GLuint vao;
glGenVertexArrays (1, &vao);
glBindVertexArray (vao);
Before creating the VBOs.
You should check out my blog post about using OpenGL with GTK+, and its related example code.
来源:https://stackoverflow.com/questions/30337845/gldrawarrays-not-working-using-gtkglarea-in-gtk3