[cogl/fosdem-2012: 5/17] examples: Adds a more advanced hairy cube example



commit 1f27bdce540f1542c88501d427fbf11a7aeea23a
Author: Robert Bragg <robert linux intel com>
Date:   Tue Jan 3 12:24:37 2012 +0000

    examples: Adds a more advanced hairy cube example
    
    This example uses the Shell Texturing technique to extrude hair from an
    arbitrary mesh (A cube in this example). It doesn't currently add fins
    on the edges so you can see shimmering when the shells become parallel
    to the viewing vector but nevertheless its quite a nice demonstration of
    using Cogl for something more than just basic textured rectangles.
    
    This example also uses the new glsl snippets api and shows how easy it
    is to customize the pipeline with your own glsl but at the same time
    build on code that's auto generated by Cogl.

 examples/Makefile.am |    6 +-
 examples/cogl-hair.c |  580 ++++++++++++++++++++++++++++++++++++++++++++++++++
 examples/leopard.jpg |  Bin 0 -> 60005 bytes
 examples/shave.jpg   |  Bin 0 -> 7427 bytes
 4 files changed, 585 insertions(+), 1 deletions(-)
---
diff --git a/examples/Makefile.am b/examples/Makefile.am
index f96ae65..ab99c8a 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -18,12 +18,14 @@ common_ldadd = \
 	$(COGL_DEP_LIBS) \
 	$(top_builddir)/cogl/libcogl.la
 
-programs = cogl-hello cogl-info cogl-msaa
+programs = cogl-hello cogl-hair cogl-info cogl-msaa
 examples_datadir = $(pkgdatadir)/examples-data
 examples_data_DATA =
 
 cogl_hello_SOURCES = cogl-hello.c
 cogl_hello_LDADD = $(common_ldadd)
+cogl_hair_SOURCES = cogl-hair.c
+cogl_hair_LDADD = $(common_ldadd)
 cogl_info_SOURCES = cogl-info.c
 cogl_info_LDADD = $(common_ldadd)
 cogl_msaa_SOURCES = cogl-msaa.c
@@ -65,6 +67,8 @@ endif
 
 EXTRA_DIST = \
 	crate.jpg \
+	leopard.jpg \
+	shave.jpg \
 	android/hello/AndroidManifest.xml \
 	android/hello/jni/Application.mk \
 	android/hello/jni/Android.mk \
diff --git a/examples/cogl-hair.c b/examples/cogl-hair.c
new file mode 100644
index 0000000..a3618e8
--- /dev/null
+++ b/examples/cogl-hair.c
@@ -0,0 +1,580 @@
+#include <cogl/cogl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#define ROTATION_SPEED 30.0f
+#define USE_COLOR_TEXTURE 1
+//#define USE_SHAVE_TEXTURE 1
+
+#ifdef USE_COLOR_TEXTURE
+
+#define TEXTURE_SIZE 128
+#define N_TEXTURES 10
+#define N_HAIRS 9000
+#define LAYER_RESOLUTION 100
+#define HAIR_LENGTH 0.5
+#define TIP_FLOP_STR "0.5"
+#define BASE_DIAMETER 0.02f
+#define TIP_DIAMETER 0.0f
+
+#else
+
+#define TEXTURE_SIZE 64
+#define N_TEXTURES 100
+#define N_HAIRS 300
+#define LAYER_RESOLUTION 320
+#define HAIR_LENGTH 1.0
+#define TIP_FLOP_STR "1.0"
+#define BASE_DIAMETER 0.1f
+#define TIP_DIAMETER 0.0f
+#endif
+
+/* The state for this example... */
+typedef struct _Data
+{
+  int framebuffer_width;
+  int framebuffer_height;
+
+  CoglMatrix view;
+
+  CoglAttribute *circle;
+  CoglIndices *indices;
+  CoglPrimitive *prim;
+  CoglTexture *shave_texture;
+  CoglTexture *color_texture;
+  CoglTexture *circle_texture;
+  CoglPipeline *cube_pipeline;
+  CoglTexture *textures[N_TEXTURES];
+  CoglPipeline *crate_pipelines[N_TEXTURES];
+
+  int hair_pos_locations[N_TEXTURES];
+  int progress_locations[N_TEXTURES];
+  int light_dir_locations[N_TEXTURES];
+
+  GTimer *timer;
+
+} Data;
+
+/* A static identity matrix initialized for convenience. */
+static CoglMatrix identity;
+/* static colors initialized for convenience. */
+static CoglColor black;
+static CoglColor white;
+
+typedef struct _Vertex
+{
+  float x, y, z;
+  float s, t;
+  float normal[3];
+} Vertex;
+
+/* A cube modelled using 4 vertices for each face.
+ *
+ * We use an index buffer when drawing the cube later so the GPU will
+ * actually read each face as 2 separate triangles.
+ */
+static Vertex vertices[] =
+{
+  /* Front face */
+  { /* pos = */ -1.0f, -1.0f,  1.0f, /* tex coords = */ 0.0f, 1.0f,
+    /* normal */ {0.0f, 0.0f, 1.0f}},
+  { /* pos = */  1.0f, -1.0f,  1.0f, /* tex coords = */ 1.0f, 1.0f,
+    /* normal */ {0.0f, 0.0f, 1.0f}},
+  { /* pos = */  1.0f,  1.0f,  1.0f, /* tex coords = */ 1.0f, 0.0f,
+    /* normal */ {0.0f, 0.0f, 1.0f}},
+  { /* pos = */ -1.0f,  1.0f,  1.0f, /* tex coords = */ 0.0f, 0.0f,
+    /* normal */ {0.0f, 0.0f, 1.0f}},
+
+  /* Back face */
+  { /* pos = */ -1.0f, -1.0f, -1.0f, /* tex coords = */ 1.0f, 0.0f,
+    /* normal */ {0.0f, 0.0f, -1.0f}},
+  { /* pos = */ -1.0f,  1.0f, -1.0f, /* tex coords = */ 1.0f, 1.0f,
+    /* normal */ {0.0f, 0.0f, -1.0f}},
+  { /* pos = */  1.0f,  1.0f, -1.0f, /* tex coords = */ 0.0f, 1.0f,
+    /* normal */ {0.0f, 0.0f, -1.0f}},
+  { /* pos = */  1.0f, -1.0f, -1.0f, /* tex coords = */ 0.0f, 0.0f,
+    /* normal */ {0.0f, 0.0f, -1.0f}},
+
+  /* Top face */
+  { /* pos = */ -1.0f,  1.0f, -1.0f, /* tex coords = */ 0.0f, 1.0f,
+    /* normal */ {0.0f, 1.0f, 0.0f}},
+  { /* pos = */ -1.0f,  1.0f,  1.0f, /* tex coords = */ 0.0f, 0.0f,
+    /* normal */ {0.0f, 1.0f, 0.0f}},
+  { /* pos = */  1.0f,  1.0f,  1.0f, /* tex coords = */ 1.0f, 0.0f,
+    /* normal */ {0.0f, 1.0f, 0.0f}},
+  { /* pos = */  1.0f,  1.0f, -1.0f, /* tex coords = */ 1.0f, 1.0f,
+    /* normal */ {0.0f, 1.0f, 0.0f}},
+
+  /* Bottom face */
+  { /* pos = */ -1.0f, -1.0f, -1.0f, /* tex coords = */ 1.0f, 1.0f,
+    /* normal */ {0.0f, -1.0f, 0.0f}},
+  { /* pos = */  1.0f, -1.0f, -1.0f, /* tex coords = */ 0.0f, 1.0f,
+    /* normal */ {0.0f, -1.0f, 0.0f}},
+  { /* pos = */  1.0f, -1.0f,  1.0f, /* tex coords = */ 0.0f, 0.0f,
+    /* normal */ {0.0f, -1.0f, 0.0f}},
+  { /* pos = */ -1.0f, -1.0f,  1.0f, /* tex coords = */ 1.0f, 0.0f,
+    /* normal */ {0.0f, -1.0f, 0.0f}},
+
+  /* Right face */
+  { /* pos = */ 1.0f, -1.0f, -1.0f, /* tex coords = */ 1.0f, 0.0f,
+    /* normal */ {1.0f, 0.0f, 0.0f}},
+  { /* pos = */ 1.0f,  1.0f, -1.0f, /* tex coords = */ 1.0f, 1.0f,
+    /* normal */ {1.0f, 0.0f, 0.0f}},
+  { /* pos = */ 1.0f,  1.0f,  1.0f, /* tex coords = */ 0.0f, 1.0f,
+    /* normal */ {1.0f, 0.0f, 0.0f}},
+  { /* pos = */ 1.0f, -1.0f,  1.0f, /* tex coords = */ 0.0f, 0.0f,
+    /* normal */ {1.0f, 0.0f, 0.0f}},
+
+  /* Left face */
+  { /* pos = */ -1.0f, -1.0f, -1.0f, /* tex coords = */ 0.0f, 0.0f,
+    /* normal */ {-1.0f, 0.0f, 0.0f}},
+  { /* pos = */ -1.0f, -1.0f,  1.0f, /* tex coords = */ 1.0f, 0.0f,
+    /* normal */ {-1.0f, 0.0f, 0.0f}},
+  { /* pos = */ -1.0f,  1.0f,  1.0f, /* tex coords = */ 1.0f, 1.0f,
+    /* normal */ {-1.0f, 0.0f, 0.0f}},
+  { /* pos = */ -1.0f,  1.0f, -1.0f, /* tex coords = */ 0.0f, 1.0f,
+    /* normal */ {-1.0f, 0.0f, 0.0f}}
+};
+
+static void
+paint (CoglFramebuffer *fb, Data *data)
+{
+  float rotation;
+  int i;
+  CoglMatrix identity;
+  int group_count;
+
+  cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR|COGL_BUFFER_BIT_DEPTH,
+                            0, 0, 0, 1);
+
+  cogl_framebuffer_push_matrix (fb);
+
+  cogl_framebuffer_translate (fb, 0, 0, -5);
+
+  /* Update the rotation based on the time the application has been
+     running so that we get a linear animation regardless of the frame
+     rate */
+  rotation = g_timer_elapsed (data->timer, NULL) * ROTATION_SPEED;
+
+  /* Rotate the cube separately around each axis.
+   *
+   * Note: Cogl matrix manipulation follows the same rules as for
+   * OpenGL. We use column-major matrices and - if you consider the
+   * transformations happening to the model - then they are combined
+   * in reverse order which is why the rotation is done last, since
+   * we want it to be a rotation around the origin, before it is
+   * scaled and translated.
+   */
+  cogl_framebuffer_rotate (fb, rotation, 0, 0, 1);
+  cogl_framebuffer_rotate (fb, rotation, 0, 1, 0);
+  cogl_framebuffer_rotate (fb, rotation, 1, 0, 0);
+
+  /* XXX: The plan is to add cogl api for drawing to an explicit framebuffer
+   * and remove the cogl_push/pop_framebuffer() functions. */
+  cogl_push_framebuffer (fb);
+
+  cogl_set_source (data->cube_pipeline);
+  cogl_primitive_draw (data->prim);
+
+  group_count = LAYER_RESOLUTION / N_TEXTURES;
+  for (i = 0; i < N_TEXTURES; i++)
+    {
+      int j;
+      cogl_set_source (data->crate_pipelines[i]);
+      for (j = 0; j < group_count; j++)
+        {
+          float progress = (group_count * i + j) / (float)LAYER_RESOLUTION;
+          float hair_pos = HAIR_LENGTH * progress;
+          float light_dir[4] = { 0, 1, 0, 0};
+
+          cogl_pipeline_set_uniform_1f (data->crate_pipelines[i],
+                                        data->progress_locations[i], progress);
+          cogl_pipeline_set_uniform_1f (data->crate_pipelines[i],
+                                        data->hair_pos_locations[i], hair_pos);
+          cogl_pipeline_set_uniform_float (data->crate_pipelines[i],
+                                           data->light_dir_locations[i],
+                                           4, /* n_components */
+                                           1, /* count */
+                                           light_dir);
+
+          /* Give Cogl some geometry to draw. */
+          cogl_primitive_draw (data->prim);
+        }
+    }
+
+  cogl_pop_framebuffer ();
+
+  cogl_framebuffer_pop_matrix (fb);
+}
+
+CoglPrimitive *
+primitive_new_p3t2t2n3 (CoglVerticesMode mode,
+                        int n_vertices,
+                        const Vertex *data)
+{
+  CoglAttributeBuffer *attribute_buffer =
+    cogl_attribute_buffer_new (n_vertices * sizeof (Vertex), data);
+  CoglAttribute *attributes[3];
+  CoglPrimitive *prim;
+  int i;
+
+  attributes[0] = cogl_attribute_new (attribute_buffer,
+                                      "cogl_position_in",
+                                      sizeof (Vertex),
+                                      offsetof (Vertex, x),
+                                      3,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
+  attributes[1] = cogl_attribute_new (attribute_buffer,
+                                      "cogl_tex_coord0_in",
+                                      sizeof (Vertex),
+                                      offsetof (Vertex, s),
+                                      2,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
+  attributes[2] = cogl_attribute_new (attribute_buffer,
+                                      "cogl_tex_coord1_in",
+                                      sizeof (Vertex),
+                                      offsetof (Vertex, s),
+                                      2,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
+  attributes[3] = cogl_attribute_new (attribute_buffer,
+                                      "cogl_normal_in",
+                                      sizeof (Vertex),
+                                      offsetof (Vertex, normal),
+                                      3,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
+
+  cogl_object_unref (attribute_buffer);
+
+  prim = cogl_primitive_new_with_attributes (mode, n_vertices,
+                                             attributes,
+                                             4);
+
+  for (i = 0; i < 3; i++)
+    cogl_object_unref (attributes[i]);
+
+  return prim;
+}
+
+static CoglAttribute *
+create_circle (int subdivisions)
+{
+  int n_verts = subdivisions + 1;
+  struct CircleVert {
+      float x, y;
+  } *verts;
+  size_t buffer_size = sizeof (struct CircleVert) * n_verts;
+  int i;
+  CoglAttributeBuffer *attribute_buffer;
+  CoglAttribute *attribute;
+
+  verts = alloca (buffer_size);
+
+  verts[0].x = 0;
+  verts[0].y = 0;
+  for (i = 1; i < n_verts; i++)
+    {
+      float angle =
+        2.0f * (float)G_PI * (1.0f/(float)subdivisions) * (float)i;
+      verts[i].x = sinf (angle);
+      verts[i].y = cosf (angle);
+    }
+  attribute_buffer = cogl_attribute_buffer_new (buffer_size, verts);
+
+  attribute = cogl_attribute_new (attribute_buffer,
+                                  "cogl_position_in",
+                                  sizeof (struct CircleVert),
+                                  offsetof (struct CircleVert, x),
+                                  2,
+                                  COGL_ATTRIBUTE_TYPE_FLOAT);
+  return attribute;
+}
+
+int
+main (int argc, char **argv)
+{
+  CoglContext *ctx;
+  CoglOnscreen *onscreen;
+  CoglFramebuffer *fb;
+  GError *error = NULL;
+  Data data;
+  float fovy, aspect, z_near, z_2d, z_far;
+  CoglDepthState depth_state;
+  CoglSnippet *snippet;
+  float diameter;
+  float hair_taper;
+  CoglHandle offscreen;
+  int i;
+  CoglPipeline *template_pipeline;
+  CoglPipeline *pipeline;
+
+  g_type_init ();
+
+  ctx = cogl_context_new (NULL, &error);
+  if (!ctx) {
+      fprintf (stderr, "Failed to create context: %s\n", error->message);
+      return 1;
+  }
+
+  data.framebuffer_width = 640;
+  data.framebuffer_height = 480;
+  onscreen = cogl_onscreen_new (ctx, data.framebuffer_width, data.framebuffer_height);
+  /* Eventually there will be an implicit allocate on first use so this
+   * will become optional... */
+  fb = COGL_FRAMEBUFFER (onscreen);
+  if (!cogl_framebuffer_allocate (fb, &error)) {
+      fprintf (stderr, "Failed to allocate framebuffer: %s\n", error->message);
+      return 1;
+  }
+
+  data.framebuffer_width = cogl_framebuffer_get_width (fb);
+  data.framebuffer_height = cogl_framebuffer_get_height (fb);
+
+  data.timer = g_timer_new ();
+
+  cogl_onscreen_show (onscreen);
+
+  cogl_framebuffer_set_viewport (fb, 0, 0,
+                                 data.framebuffer_width, data.framebuffer_height);
+
+  fovy = 60; /* y-axis field of view */
+  aspect = (float)data.framebuffer_width/(float)data.framebuffer_height;
+  z_near = 0.1; /* distance to near clipping plane */
+  z_2d = 1000; /* position to 2d plane */
+  z_far = 2000; /* distance to far clipping plane */
+
+  cogl_framebuffer_perspective (fb, fovy, aspect, z_near, z_far);
+
+  /* Initialize some convenient constants */
+  cogl_matrix_init_identity (&identity);
+  cogl_color_set_from_4ub (&black, 0x00, 0x00, 0x00, 0xff);
+  cogl_color_set_from_4ub (&white, 0xff, 0xff, 0xff, 0xff);
+
+  /* rectangle indices allow the GPU to interpret a list of quads (the
+   * faces of our cube) as a list of triangles.
+   *
+   * Since this is a very common thing to do
+   * cogl_get_rectangle_indices() is a convenience function for
+   * accessing internal index buffers that can be shared.
+   */
+  data.indices = cogl_get_rectangle_indices (6 /* n_rectangles */);
+  data.prim = primitive_new_p3t2t2n3 (COGL_VERTICES_MODE_TRIANGLES,
+                                      G_N_ELEMENTS (vertices),
+                                      vertices);
+  /* Each face will have 6 indices so we have 6 * 6 indices in total... */
+  cogl_primitive_set_indices (data.prim,
+                              data.indices,
+                              6 * 6);
+
+  data.color_texture = cogl_texture_new_from_file (COGL_EXAMPLES_DATA "leopard.jpg",
+                                                   COGL_TEXTURE_NO_SLICING,
+                                                   COGL_PIXEL_FORMAT_ANY,
+                                                   NULL);
+  if (!data.color_texture)
+    g_error ("Failed to load texture");
+
+#ifdef USE_SHAVE_TEXTURE
+  data.shave_texture = cogl_texture_new_from_file (COGL_EXAMPLES_DATA "shave.jpg",
+                                                    COGL_TEXTURE_NO_SLICING,
+                                                    COGL_PIXEL_FORMAT_ANY,
+                                                    NULL);
+  if (!data.shave_texture)
+    g_error ("Failed to load texture");
+#endif
+
+  data.circle_texture =
+    COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, TEXTURE_SIZE, TEXTURE_SIZE,
+                                                 COGL_PIXEL_FORMAT_RGBA_8888, NULL));
+  offscreen = cogl_offscreen_new_to_texture (data.circle_texture);
+  cogl_push_framebuffer (offscreen);
+
+  data.circle = create_circle (360);
+
+  cogl_framebuffer_clear4f (COGL_FRAMEBUFFER (offscreen),
+                            COGL_BUFFER_BIT_COLOR, 0, 0, 0, 0);
+
+  cogl_framebuffer_identity_matrix (COGL_FRAMEBUFFER (offscreen));
+
+  cogl_set_source_color (&white);
+  cogl_draw_attributes (COGL_VERTICES_MODE_TRIANGLE_FAN,
+                        0, /* first vertex */
+                        361, /* n_vertices */
+                        &data.circle,
+                        1); /* n_attributes */
+
+  cogl_pop_framebuffer ();
+  cogl_object_unref (offscreen);
+
+  pipeline = cogl_pipeline_new ();
+  cogl_pipeline_set_layer_texture (pipeline, 0, data.circle_texture);
+  cogl_set_source (pipeline);
+
+  diameter = BASE_DIAMETER;
+  hair_taper = (BASE_DIAMETER - TIP_DIAMETER) / N_TEXTURES;
+
+  for (i = 0; i < N_TEXTURES; i++)
+    {
+      CoglHandle offscreen;
+      int j;
+
+      data.textures[i] =
+        COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, 256, 256,
+                                                     COGL_PIXEL_FORMAT_RGBA_8888, NULL));
+      offscreen = cogl_offscreen_new_to_texture (data.textures[i]);
+      cogl_push_framebuffer (offscreen);
+
+      cogl_framebuffer_clear4f (COGL_FRAMEBUFFER (offscreen),
+                                COGL_BUFFER_BIT_COLOR, 0, 0, 0, 0);
+#ifdef USE_COLOR_TEXTURE
+      cogl_pipeline_set_color4f (pipeline, 0.3, 0.3, 0.3, 1.0);
+#else
+      cogl_pipeline_set_color4ub (pipeline, 0x7f, 0x4e, 0x00, 0xff);
+#endif
+
+      srand (7025);
+      for (j = 0; j < N_HAIRS; j++)
+        {
+          float x = ((rand() / (float)RAND_MAX) * 2) - 1;
+          float y = ((rand() / (float)RAND_MAX) * 2) - 1;
+
+          cogl_rectangle (x, y, x + diameter, y + diameter);
+        }
+
+#ifdef USE_COLOR_TEXTURE
+      cogl_pipeline_set_color4f (pipeline, 1, 1, 1, 1);
+#else
+      cogl_pipeline_set_color4ub (pipeline, 0xf8, 0x98, 0x00, 0xff);
+#endif
+
+      srand (7025);
+      for (j = 0; j < N_HAIRS; j++)
+        {
+          float x = ((rand() / (float)RAND_MAX) * 2) - 1;
+          float y = ((rand() / (float)RAND_MAX) * 2) - 1;
+          float shadow_offset = diameter / 4.0f;
+          x += shadow_offset;
+          y += shadow_offset;
+
+          cogl_rectangle (x, y, x + diameter, y + diameter);
+        }
+
+      cogl_pop_framebuffer ();
+      cogl_object_unref (offscreen);
+
+      diameter -= hair_taper;
+    }
+
+  data.cube_pipeline = cogl_pipeline_new ();
+  cogl_pipeline_set_color4ub (data.cube_pipeline, 0x53, 0x32, 0x09, 0xff);
+
+  cogl_depth_state_init (&depth_state);
+  cogl_depth_state_set_test_enabled (&depth_state, TRUE);
+  cogl_depth_state_set_write_enabled (&depth_state, TRUE);
+  cogl_pipeline_set_depth_state (data.cube_pipeline, &depth_state, NULL);
+
+  template_pipeline = cogl_pipeline_new ();
+
+  /* TODO: Consider adding a mechanism that lets developers request
+   * that specific attributes be read-write. */
+  snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX_TRANSFORM,
+                              /* declarations */
+                              "uniform float hair_pos;\n" /* range [0,length] */
+                              "uniform float progress;\n" /* range [0,1] */
+                              "uniform vec4 light_dir;\n"
+
+                              "float tip_flop = " TIP_FLOP_STR ";\n"
+                              "vec4 normal4;\n"
+                              "vec4 hair_force_dir = vec4 (0.0, -1.0, 0.0, 0.0);\n"
+                              "float force_factor;\n"
+
+                              "varying vec4 world_normal;\n",
+                              NULL); /* pre */
+
+  cogl_snippet_set_replace (snippet,
+                            "  normal4 = vec4 (cogl_normal_in, 0.0);\n"
+                            "  cogl_position_out = cogl_position_in + normal4 * hair_pos;\n"
+                            "  cogl_position_out = cogl_modelview_projection_matrix * cogl_position_out;\n"
+                            "  force_factor = pow (progress, 3.0) * tip_flop;\n"
+                            "  cogl_position_out += hair_force_dir * force_factor;\n"
+                            "  world_normal = cogl_modelview_matrix * normal4;\n");
+
+  cogl_pipeline_add_snippet (template_pipeline, snippet);
+  cogl_object_unref (snippet);
+
+  /* We need to make sure that we don't write transparent fragments to the
+   * depth buffer... */
+  snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+                              /* declarations */
+#ifdef USE_SHAVE_TEXTURE
+                              "unform float progress;\n"
+#endif
+                              "uniform vec4 light_dir;\n"
+                              "varying vec4 world_normal;\n"
+                              "vec4 ambient = vec4 (0.2, 0.2, 0.2, 0.0);\n",
+
+                              /* code */
+                              "  if (cogl_color_out.a < 0.25) discard;\n"
+#ifdef USE_SHAVE_TEXTURE
+                              /* FIXME: this relies in internal detail of cogl's codegen... */
+                              "  if (texture2D (cogl_sampler2, cogl_tex_coord_in[2].st).r > progress))\n"
+                              "    discard;\n"
+#endif
+                              "  cogl_color_out += dot (light_dir, world_normal) * ambient;\n");
+
+  cogl_pipeline_add_snippet (template_pipeline, snippet);
+  cogl_object_unref (snippet);
+
+
+  /* Since the box is made of multiple triangles that will overlap
+   * when drawn and we don't control the order they are drawn in, we
+   * enable depth testing to make sure that triangles that shouldn't
+   * be visible get culled by the GPU. */
+  cogl_depth_state_init (&depth_state);
+  cogl_depth_state_set_test_enabled (&depth_state, TRUE);
+
+  cogl_pipeline_set_depth_state (template_pipeline, &depth_state, NULL);
+
+
+#ifdef USE_COLOR_TEXTURE
+  cogl_pipeline_set_layer_texture (template_pipeline, 1, data.color_texture);
+#endif
+
+#ifdef USE_SHAVE_TEXTURE
+  cogl_pipeline_set_layer_texture (template_pipeline, 2, data.shave_texture);
+  /* We want the layer combining to skip this layer since we just want to
+   * refer to the texture in our glsl snippet... */
+  /* XXX: double check that cogl-pipeline-fragend-glsl.c doesn't emit code
+   * for REPLACE (PREVIOUS) */
+  /* FIXME: we get a very unhelpful error if we put a semicolon at the end
+   * of a blend string... */
+  cogl_pipeline_set_layer_combine (template_pipeline,
+                                   2, "RGBA=REPLACE(PREVIOUS)", NULL);
+#endif
+
+  /* Create a pipeline for each texture we have to avoid modifying pipelines... */
+  /* XXX: Can we define that the semantics for copying a pipeline are that
+   * uniform locations for the new pipeline are the same as for the parent
+   * except they might change if anything other than uniform values are
+   * changed. */
+  for (i = 0; i < N_TEXTURES; i++)
+    {
+      data.crate_pipelines[i] = cogl_pipeline_copy (template_pipeline);
+      cogl_pipeline_set_layer_texture (data.crate_pipelines[i], 0, data.textures[i]);
+      data.hair_pos_locations[i] =
+        cogl_pipeline_get_uniform_location (data.crate_pipelines[i], "hair_pos");
+      data.progress_locations[i] =
+        cogl_pipeline_get_uniform_location (data.crate_pipelines[i], "progress");
+      data.light_dir_locations[i] =
+        cogl_pipeline_get_uniform_location (data.crate_pipelines[i], "light_dir");
+    }
+
+  while (1)
+    {
+      paint (fb, &data);
+      cogl_framebuffer_swap_buffers (fb);
+    }
+
+  return 0;
+}
+
diff --git a/examples/leopard.jpg b/examples/leopard.jpg
new file mode 100644
index 0000000..5ba21a6
Binary files /dev/null and b/examples/leopard.jpg differ
diff --git a/examples/shave.jpg b/examples/shave.jpg
new file mode 100644
index 0000000..5c92f2a
Binary files /dev/null and b/examples/shave.jpg differ



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]