demos: Update the GtkGLArea demo code

Same way we updated the testglarea test code.

https://bugzilla.gnome.org/show_bug.cgi?id=741946
This commit is contained in:
Emmanuele Bassi 2015-02-05 16:39:53 +00:00
parent b87034a985
commit 01d1cdc76c

View File

@ -3,6 +3,7 @@
* GtkGLArea is a widget that allows custom drawing using OpenGL calls.
*/
#include <math.h>
#include <gtk/gtk.h>
#include <epoxy/gl.h>
@ -23,35 +24,274 @@ enum {
static float rotation_angles[N_AXIS] = { 0.0 };
/* 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,
const char *src)
{
GLuint shader;
int status;
shader = glCreateShader (type);
glShaderSource (shader, 1, &src, 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\n",
type == GL_VERTEX_SHADER ? "vertex" : "fragment",
buffer);
g_free (buffer);
glDeleteShader (shader);
return 0;
}
return shader;
}
/* The code for the vertex shader we are going to use */
static const char *vertex_shader_code =
"#version 330\n" \
"\n" \
"layout(location = 0) in vec4 position;\n" \
"uniform mat4 mvp;\n"
"void main() {\n" \
" gl_Position = mvp * position;\n" \
"}";
/* The code for the fragment shader we are going to use */
static const char *fragment_shader_code =
"#version 330\n" \
"\n" \
"out vec4 outputColor;\n" \
"void main() {\n" \
" float lerpVal = gl_FragCoord.y / 400.0f;\n" \
" outputColor = mix(vec4(1.0f, 0.85f, 0.35f, 1.0f), vec4(0.2f, 0.2f, 0.2f, 1.0f), lerpVal);\n" \
"}";
/* Initialize the shaders and link them into a program */
static void
init_shaders (GLuint *program_out,
GLuint *mvp_out)
{
GLuint vertex, fragment;
GLuint program = 0;
GLuint mvp = 0;
int status;
vertex = create_shader (GL_VERTEX_SHADER, vertex_shader_code);
if (vertex == 0)
{
*program_out = 0;
return;
}
fragment = create_shader (GL_FRAGMENT_SHADER, fragment_shader_code);
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\n", buffer);
g_free (buffer);
glDeleteProgram (program);
program = 0;
goto out;
}
/* Get the location of the "mvp" uniform */
mvp = glGetUniformLocation (program, "mvp");
glDetachShader (program, vertex);
glDetachShader (program, fragment);
out:
glDeleteShader (vertex);
glDeleteShader (fragment);
if (program_out != NULL)
*program_out = program;
if (mvp_out != NULL)
*mvp_out = mvp;
}
static void
compute_mvp (float *res,
float phi,
float theta,
float psi)
{
float x = phi * (G_PI / 180.f);
float y = theta * (G_PI / 180.f);
float z = psi * (G_PI / 180.f);
float c1 = cosf (x), s1 = sinf (x);
float c2 = cosf (y), s2 = sinf (y);
float c3 = cosf (z), s3 = sinf (z);
float c3c2 = c3 * c2;
float s3c1 = s3 * c1;
float c3s2s1 = c3 * s2 * s1;
float s3s1 = s3 * s1;
float c3s2c1 = c3 * s2 * c1;
float s3c2 = s3 * c2;
float c3c1 = c3 * c1;
float s3s2s1 = s3 * s2 * s1;
float c3s1 = c3 * s1;
float s3s2c1 = s3 * s2 * c1;
float c2s1 = c2 * s1;
float c2c1 = c2 * c1;
/* initialize to the identity matrix */
res[0] = 1.f; res[4] = 0.f; res[8] = 0.f; res[12] = 0.f;
res[1] = 0.f; res[5] = 1.f; res[9] = 0.f; res[13] = 0.f;
res[2] = 0.f; res[6] = 0.f; res[10] = 1.f; res[14] = 0.f;
res[3] = 0.f; res[7] = 0.f; res[11] = 0.f; res[15] = 1.f;
/* apply all three rotations using the three matrices:
*
* c3 s3 0 c2 0 -s2 1 0 0
* -s3 c3 0 0 1 0 0 c1 s1
* 0 0 1 s2 0 c2 0 -s1 c1
*/
res[0] = c3c2; res[4] = s3c1 + c3s2s1; res[8] = s3s1 - c3s2c1; res[12] = 0.f;
res[1] = -s3c2; res[5] = c3c1 - s3s2s1; res[9] = c3s1 + s3s2c1; res[13] = 0.f;
res[2] = s2; res[6] = -c2s1; res[10] = c2c1; res[14] = 0.f;
res[3] = 0.f; res[7] = 0.f; res[11] = 0.f; res[15] = 1.f;
}
static GLuint position_buffer;
static GLuint program;
static GLuint mvp_location;
/* We need to set up our state when we realize the GtkGLArea widget */
static void
realize (GtkWidget *widget)
{
gtk_gl_area_make_current (GTK_GL_AREA (widget));
init_buffers (&position_buffer, NULL);
init_shaders (&program, &mvp_location);
}
/* We should tear down the state when unrealizing */
static void
unrealize (GtkWidget *widget)
{
gtk_gl_area_make_current (GTK_GL_AREA (widget));
glDeleteBuffers (1, &position_buffer);
glDeleteProgram (program);
}
static void
draw_triangle (void)
{
glColor3f (1.0f, 0.85f, 0.35f);
glBegin (GL_TRIANGLES);
{
glVertex3f ( 0.0, 0.6, 0.0);
glVertex3f (-0.2, -0.3, 0.0);
glVertex3f ( 0.2, -0.3, 0.0);
}
glEnd ();
float mvp[16];
/* Compute the model view projection matrix using the
* rotation angles specified through the GtkRange widgets
*/
compute_mvp (mvp,
rotation_angles[X_AXIS],
rotation_angles[Y_AXIS],
rotation_angles[Z_AXIS]);
/* Use our shaders */
glUseProgram (program);
/* Update the "mvp" matrix we use in the shader */
glUniformMatrix4fv (mvp_location, 1, GL_FALSE, &mvp[0]);
/* 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);
}
/* The main rendering callback */
static gboolean
render (GtkGLArea *area,
GdkGLContext *context)
{
/* Clear the viewport */
glClearColor (0.5, 0.5, 0.5, 1.0);
glClear (GL_COLOR_BUFFER_BIT);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
glRotatef (rotation_angles[X_AXIS], 1, 0, 0);
glRotatef (rotation_angles[Y_AXIS], 0, 1, 0);
glRotatef (rotation_angles[Z_AXIS], 0, 0, 1);
/* Draw our object */
draw_triangle ();
/* Flush the contents of the pipeline */
glFlush ();
return TRUE;
@ -138,7 +378,7 @@ create_glarea_window (GtkWidget *do_widget)
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_screen (GTK_WINDOW (window), gtk_widget_get_screen (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "GtkGLArea - Golden Triangle");
gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
gtk_container_set_border_width (GTK_CONTAINER (window), 12);
g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
@ -151,7 +391,13 @@ create_glarea_window (GtkWidget *do_widget)
gtk_widget_set_vexpand (gl_area, TRUE);
gtk_container_add (GTK_CONTAINER (box), gl_area);
/* the main "draw" call for GtkGLArea */
/* 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);
controls = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE);