summaryrefslogtreecommitdiff
path: root/tests/testglarea.c
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@gnome.org>2015-01-30 17:20:44 +0000
committerEmmanuele Bassi <ebassi@gnome.org>2015-02-09 19:10:30 +0000
commitb87034a985523f71783c1f0b16a27da8a6738de5 (patch)
tree68bc213f71ea005468621f5ec18b665ad4d9a9f6 /tests/testglarea.c
parent1d3cc65e894d8342b7bf72e51e036be7a5c4d339 (diff)
downloadgtk+-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
Diffstat (limited to 'tests/testglarea.c')
-rw-r--r--tests/testglarea.c256
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);