diff options
author | Emmanuele Bassi <ebassi@gnome.org> | 2015-01-30 17:20:44 +0000 |
---|---|---|
committer | Emmanuele Bassi <ebassi@gnome.org> | 2015-02-09 19:10:30 +0000 |
commit | b87034a985523f71783c1f0b16a27da8a6738de5 (patch) | |
tree | 68bc213f71ea005468621f5ec18b665ad4d9a9f6 | |
parent | 1d3cc65e894d8342b7bf72e51e036be7a5c4d339 (diff) | |
download | gtk+-b87034a985523f71783c1f0b16a27da8a6738de5.tar.gz |
tests: Update testglarea
Since we dropped the legacy OpenGL compatibility profile, we need to use
recent OpenGL APi and concepts. This also means that the example code
gets a tad more complicated.
https://bugzilla.gnome.org/show_bug.cgi?id=741946
-rw-r--r-- | tests/testglarea.c | 256 |
1 files changed, 240 insertions, 16 deletions
diff --git a/tests/testglarea.c b/tests/testglarea.c index 23e5d8fab7..41ac705098 100644 --- a/tests/testglarea.c +++ b/tests/testglarea.c @@ -1,3 +1,4 @@ +#include <math.h> #include <stdlib.h> #include <gtk/gtk.h> @@ -15,17 +16,244 @@ static float rotation_angles[N_AXIS] = { 0.0 }; static GtkWidget *gl_area; +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, +}; + +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); + + 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; +} + +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; +} + +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" \ +"}"; + +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" \ +"}"; + +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; + } + + 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; + +static void +realize (GtkWidget *widget) +{ + gtk_gl_area_make_current (GTK_GL_AREA (widget)); + + init_buffers (&position_buffer, NULL); + init_shaders (&program, &mvp_location); +} + +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]; + + g_assert (position_buffer != 0); + g_assert (program != 0); + + compute_mvp (mvp, + rotation_angles[X_AXIS], + rotation_angles[Y_AXIS], + rotation_angles[Z_AXIS]); + + glUseProgram (program); + glUniformMatrix4fv (mvp_location, 1, GL_FALSE, &mvp[0]); + + glBindBuffer (GL_ARRAY_BUFFER, position_buffer); + glEnableVertexAttribArray (0); + glVertexAttribPointer (0, 4, GL_FLOAT, GL_FALSE, 0, 0); + + glDrawArrays (GL_TRIANGLES, 0, 3); + + glDisableVertexAttribArray (0); + glUseProgram (0); } static gboolean @@ -35,12 +263,6 @@ render (GtkGLArea *area, 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_triangle (); glFlush (); @@ -120,8 +342,8 @@ main (int argc, char *argv[]) */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (window), "GtkGLArea - Golden Triangle"); - gtk_window_set_default_size (GTK_WINDOW (window), 400, 400); + gtk_window_set_title (GTK_WINDOW (window), "GtkGLArea - Triangle"); + 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 (gtk_main_quit), NULL); @@ -134,6 +356,8 @@ main (int argc, char *argv[]) gtk_widget_set_hexpand (gl_area, TRUE); gtk_widget_set_vexpand (gl_area, TRUE); gtk_container_add (GTK_CONTAINER (box), gl_area); + g_signal_connect (gl_area, "realize", G_CALLBACK (realize), NULL); + g_signal_connect (gl_area, "unrealize", G_CALLBACK (unrealize), NULL); g_signal_connect (gl_area, "render", G_CALLBACK (render), NULL); gtk_widget_show (gl_area); |