bool ImGui_ImplGtk3Cogl_CreateDeviceObjects()
{
    g_ColorPipeline = cogl_pipeline_new(g_Context);
    g_ImagePipeline = cogl_pipeline_new(g_Context);

    CoglError *error = NULL;
    if (!cogl_pipeline_set_blend(g_ColorPipeline,
                                 "RGB = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))"
                                 "A = ADD(SRC_COLOR[A], DST_COLOR*(1-SRC_COLOR[A]))",
                                 &error))
    {
        g_warning("Blending: %s", error->message);
        g_error_free(error);
        return false;
    }
    cogl_pipeline_set_cull_face_mode(g_ColorPipeline, COGL_PIPELINE_CULL_FACE_MODE_NONE);

    CoglDepthState depth_state;

    cogl_depth_state_init(&depth_state);
    cogl_depth_state_set_test_enabled(&depth_state, FALSE);
    if (!cogl_pipeline_set_depth_state(g_ColorPipeline, &depth_state, &error))
    {
        g_warning("Depth: %s", error->message);
        g_error_free(error);
        return false;
    }

    if (!cogl_pipeline_set_blend(g_ImagePipeline,
                                 "RGB = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))"
                                 "A = ADD(SRC_COLOR[A], DST_COLOR*(1-SRC_COLOR[A]))",
                                 &error))
    {
        g_warning("Blending: %s", error->message);
        g_error_free(error);
        return false;
    }
    cogl_pipeline_set_cull_face_mode(g_ImagePipeline, COGL_PIPELINE_CULL_FACE_MODE_NONE);

    if (!cogl_pipeline_set_depth_state(g_ImagePipeline, &depth_state, &error))
    {
        g_warning("Depth: %s", error->message);
        g_error_free(error);
        return false;
    }

    ImGui_ImplGtk3Cogl_CreateFontsTexture();

    /* Disable depth buffer since we're not using it. */
    //cogl_framebuffer_set_depth_write_enabled(g_Framebuffer, FALSE);

    return true;
}
Exemple #2
0
static gboolean
draw_rectangle (TestState *state,
                int x,
                int y,
                TestDepthState *rect_state)
{
  guint8 Cr = MASK_RED (rect_state->color);
  guint8 Cg = MASK_GREEN (rect_state->color);
  guint8 Cb = MASK_BLUE (rect_state->color);
  guint8 Ca = MASK_ALPHA (rect_state->color);
  CoglHandle pipeline;
  CoglDepthState depth_state;

  cogl_depth_state_init (&depth_state);
  cogl_depth_state_set_test_enabled (&depth_state, rect_state->test_enable);
  cogl_depth_state_set_test_function (&depth_state, rect_state->test_function);
  cogl_depth_state_set_write_enabled (&depth_state, rect_state->write_enable);
  cogl_depth_state_set_range (&depth_state,
                              rect_state->range_near,
                              rect_state->range_far);

  pipeline = cogl_pipeline_new ();
  if (!cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL))
    {
      cogl_object_unref (pipeline);
      return FALSE;
    }

  cogl_pipeline_set_color4ub (pipeline, Cr, Cg, Cb, Ca);

  cogl_set_source (pipeline);

  cogl_push_matrix ();
  cogl_translate (0, 0, rect_state->depth);
  cogl_rectangle (x * QUAD_WIDTH,
                  y * QUAD_WIDTH,
                  x * QUAD_WIDTH + QUAD_WIDTH,
                  y * QUAD_WIDTH + QUAD_WIDTH);
  cogl_pop_matrix ();

  cogl_object_unref (pipeline);

  return TRUE;
}
static void
draw_entity_camera_frustum (RigEngine *engine,
                            RutEntity *entity,
                            CoglFramebuffer *fb)
{
  RutCamera *camera =
    rut_entity_get_component (entity, RUT_COMPONENT_TYPE_CAMERA);
  CoglPrimitive *primitive = rut_camera_create_frustum_primitive (camera);
  CoglPipeline *pipeline = cogl_pipeline_new (rut_cogl_context);
  CoglDepthState depth_state;

  /* enable depth testing */
  cogl_depth_state_init (&depth_state);
  cogl_depth_state_set_test_enabled (&depth_state, TRUE);
  cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL);

  rut_util_draw_jittered_primitive3f (fb, primitive, 0.8, 0.6, 0.1);

  cogl_object_unref (primitive);
  cogl_object_unref (pipeline);
}
static void
clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect)
{
  ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect);
  ClutterDeformEffectPrivate *priv = self->priv;
  CoglHandle material;
  CoglPipeline *pipeline;
  CoglDepthState depth_state;
  CoglFramebuffer *fb = cogl_get_draw_framebuffer ();

  if (priv->is_dirty)
    {
      ClutterRect rect;
      gboolean mapped_buffer;
      CoglVertexP3T2C4 *verts;
      ClutterActor *actor;
      gfloat width, height;
      guint opacity;
      gint i, j;

      actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
      opacity = clutter_actor_get_paint_opacity (actor);

      /* if we don't have a target size, fall back to the actor's
       * allocation, though wrong it might be
       */
      if (clutter_offscreen_effect_get_target_rect (effect, &rect))
        {
          width = clutter_rect_get_width (&rect);
          height = clutter_rect_get_height (&rect);
        }
      else
        clutter_actor_get_size (actor, &width, &height);

      /* XXX ideally, the sub-classes should tell us what they
       * changed in the texture vertices; we then would be able to
       * avoid resubmitting the same data, if it did not change. for
       * the time being, we resubmit everything
       */
      verts = cogl_buffer_map (COGL_BUFFER (priv->buffer),
                               COGL_BUFFER_ACCESS_WRITE,
                               COGL_BUFFER_MAP_HINT_DISCARD);

      /* If the map failed then we'll resort to allocating a temporary
         buffer */
      if (verts == NULL)
        {
          mapped_buffer = FALSE;
          verts = g_malloc (sizeof (*verts) * priv->n_vertices);
        }
      else
        mapped_buffer = TRUE;

      for (i = 0; i < priv->y_tiles + 1; i++)
        {
          for (j = 0; j < priv->x_tiles + 1; j++)
            {
              CoglVertexP3T2C4 *vertex_out;
              CoglTextureVertex vertex;

              /* CoglTextureVertex isn't an ideal structure to use for
                 this because it contains a CoglColor. The internal
                 layout of CoglColor is mean to be private so Clutter
                 can not pass a pointer to it as a vertex
                 attribute. Also it contains padding so we end up
                 storing more data in the vertex buffer than we need
                 to. Instead we let the application modify a dummy
                 vertex and then copy the details back out to a more
                 well-defined struct */

              vertex.tx = (float) j / priv->x_tiles;
              vertex.ty = (float) i / priv->y_tiles;

              vertex.x = width * vertex.tx;
              vertex.y = height * vertex.ty;
              vertex.z = 0.0f;

              cogl_color_init_from_4ub (&vertex.color, 255, 255, 255, opacity);

              clutter_deform_effect_deform_vertex (self,
                                                   width, height,
                                                   &vertex);

              vertex_out = verts + i * (priv->x_tiles + 1) + j;

              vertex_out->x = vertex.x;
              vertex_out->y = vertex.y;
              vertex_out->z = vertex.z;
              vertex_out->s = vertex.tx;
              vertex_out->t = vertex.ty;
              vertex_out->r = cogl_color_get_red_byte (&vertex.color);
              vertex_out->g = cogl_color_get_green_byte (&vertex.color);
              vertex_out->b = cogl_color_get_blue_byte (&vertex.color);
              vertex_out->a = cogl_color_get_alpha_byte (&vertex.color);
            }
        }

      if (mapped_buffer)
        cogl_buffer_unmap (COGL_BUFFER (priv->buffer));
      else
        {
          cogl_buffer_set_data (COGL_BUFFER (priv->buffer),
                                0, /* offset */
                                verts,
                                sizeof (*verts) * priv->n_vertices);
          g_free (verts);
        }

      priv->is_dirty = FALSE;
    }

  material = clutter_offscreen_effect_get_target (effect);
  pipeline = COGL_PIPELINE (material);

  /* enable depth testing */
  cogl_depth_state_init (&depth_state);
  cogl_depth_state_set_test_enabled (&depth_state, TRUE);
  cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL);

  /* enable backface culling if we have a back material */
  if (priv->back_pipeline != NULL)
    cogl_pipeline_set_cull_face_mode (pipeline,
                                      COGL_PIPELINE_CULL_FACE_MODE_BACK);

  /* draw the front */
  if (material != NULL)
    cogl_framebuffer_draw_primitive (fb, pipeline, priv->primitive);

  /* draw the back */
  if (priv->back_pipeline != NULL)
    {
      CoglPipeline *back_pipeline;

      /* We probably shouldn't be modifying the user's material so
         instead we make a temporary copy */
      back_pipeline = cogl_pipeline_copy (priv->back_pipeline);
      cogl_pipeline_set_depth_state (back_pipeline, &depth_state, NULL);
      cogl_pipeline_set_cull_face_mode (back_pipeline,
                                        COGL_PIPELINE_CULL_FACE_MODE_FRONT);

      cogl_framebuffer_draw_primitive (fb, back_pipeline, priv->primitive);

      cogl_object_unref (back_pipeline);
    }

  if (G_UNLIKELY (priv->lines_primitive != NULL))
    {
      CoglContext *ctx =
        clutter_backend_get_cogl_context (clutter_get_default_backend ());
      CoglPipeline *lines_pipeline = cogl_pipeline_new (ctx);
      cogl_pipeline_set_color4f (lines_pipeline, 1.0, 0, 0, 1.0);
      cogl_framebuffer_draw_primitive (fb, lines_pipeline,
                                       priv->lines_primitive);
      cogl_object_unref (lines_pipeline);
    }
}
Exemple #5
0
int
main (int argc, char **argv)
{
  CoglContext *ctx;
  CoglOnscreen *onscreen;
  CoglFramebuffer *fb;
  GError *error = NULL;
  Data data;
  PangoRectangle hello_label_size;
  float fovy, aspect, z_near, z_2d, z_far;
  CoglDepthState depth_state;
  CoglBool has_swap_notify;

  ctx = cogl_context_new (NULL, &error);
  if (!ctx) {
      fprintf (stderr, "Failed to create context: %s\n", error->message);
      return 1;
  }

  onscreen = cogl_onscreen_new (ctx, 640, 480);
  fb = COGL_FRAMEBUFFER (onscreen);
  data.fb = fb;
  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);

  /* Since the pango renderer emits geometry in pixel/device coordinates
   * and the anti aliasing is implemented with the assumption that the
   * geometry *really* does end up pixel aligned, we setup a modelview
   * matrix so that for geometry in the plane z = 0 we exactly map x
   * coordinates in the range [0,stage_width] and y coordinates in the
   * range [0,stage_height] to the framebuffer extents with (0,0) being
   * the top left.
   *
   * This is roughly what Clutter does for a ClutterStage, but this
   * demonstrates how it is done manually using Cogl.
   */
  cogl_matrix_init_identity (&data.view);
  cogl_matrix_view_2d_in_perspective (&data.view, fovy, aspect, z_near, z_2d,
                                      data.framebuffer_width,
                                      data.framebuffer_height);
  cogl_framebuffer_set_modelview_matrix (fb, &data.view);

  /* Initialize some convenient constants */
  cogl_matrix_init_identity (&identity);
  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 (ctx, 6 /* n_rectangles */);
  data.prim = cogl_primitive_new_p3t2 (ctx, 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);

  /* Load a jpeg crate texture from a file */
  printf ("crate.jpg (CC by-nc-nd http://bit.ly/9kP45T) ShadowRunner27 http://bit.ly/m1YXLh\n");
  data.texture = cogl_texture_new_from_file (COGL_EXAMPLES_DATA "crate.jpg",
                                             COGL_TEXTURE_NO_SLICING,
                                             COGL_PIXEL_FORMAT_ANY,
                                             &error);
  if (!data.texture)
    g_error ("Failed to load texture: %s", error->message);

  /* a CoglPipeline conceptually describes all the state for vertex
   * processing, fragment processing and blending geometry. When
   * drawing the geometry for the crate this pipeline says to sample a
   * single texture during fragment processing... */
  data.crate_pipeline = cogl_pipeline_new (ctx);
  cogl_pipeline_set_layer_texture (data.crate_pipeline, 0, data.texture);

  /* 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 (data.crate_pipeline, &depth_state, NULL);

  /* Setup a Pango font map and context */

  data.pango_font_map = COGL_PANGO_FONT_MAP (cogl_pango_font_map_new (ctx));

  cogl_pango_font_map_set_use_mipmapping (data.pango_font_map, TRUE);

  data.pango_context =
    pango_font_map_create_context (PANGO_FONT_MAP (data.pango_font_map));

  data.pango_font_desc = pango_font_description_new ();
  pango_font_description_set_family (data.pango_font_desc, "Sans");
  pango_font_description_set_size (data.pango_font_desc, 30 * PANGO_SCALE);

  /* Setup the "Hello Cogl" text */

  data.hello_label = pango_layout_new (data.pango_context);
  pango_layout_set_font_description (data.hello_label, data.pango_font_desc);
  pango_layout_set_text (data.hello_label, "Hello Cogl", -1);

  pango_layout_get_extents (data.hello_label, NULL, &hello_label_size);
  data.hello_label_width = PANGO_PIXELS (hello_label_size.width);
  data.hello_label_height = PANGO_PIXELS (hello_label_size.height);

  data.swap_ready = TRUE;

  has_swap_notify =
    cogl_has_feature (ctx, COGL_FEATURE_ID_SWAP_BUFFERS_EVENT);

  if (has_swap_notify)
    cogl_onscreen_add_swap_buffers_callback (COGL_ONSCREEN (fb),
                                             swap_notify_cb,
                                             &data);

  while (1)
    {
      CoglPollFD *poll_fds;
      int n_poll_fds;
      int64_t timeout;

      if (data.swap_ready)
        {
          paint (&data);
          cogl_onscreen_swap_buffers (COGL_ONSCREEN (fb));
        }

      cogl_poll_get_info (ctx, &poll_fds, &n_poll_fds, &timeout);

      if (!has_swap_notify)
        {
          /* If the winsys doesn't support swap event notification
             then we'll just redraw constantly */
          data.swap_ready = TRUE;
          timeout = 0;
        }

      g_poll ((GPollFD *) poll_fds, n_poll_fds,
              timeout == -1 ? -1 : timeout / 1000);

      cogl_poll_dispatch (ctx, poll_fds, n_poll_fds);
    }

  return 0;
}
Exemple #6
0
static CoglBool
draw_rectangle (TestState *state,
                int x,
                int y,
                TestDepthState *rect_state,
                CoglBool legacy_mode)
{
  uint8_t Cr = MASK_RED (rect_state->color);
  uint8_t Cg = MASK_GREEN (rect_state->color);
  uint8_t Cb = MASK_BLUE (rect_state->color);
  uint8_t Ca = MASK_ALPHA (rect_state->color);
  CoglPipeline *pipeline;
  CoglDepthState depth_state;

  cogl_depth_state_init (&depth_state);
  cogl_depth_state_set_test_enabled (&depth_state, rect_state->test_enable);
  cogl_depth_state_set_test_function (&depth_state, rect_state->test_function);
  cogl_depth_state_set_write_enabled (&depth_state, rect_state->write_enable);
  cogl_depth_state_set_range (&depth_state,
                              rect_state->range_near,
                              rect_state->range_far);

  pipeline = cogl_pipeline_new (test_ctx);
  if (!cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL))
    {
      cogl_object_unref (pipeline);
      return FALSE;
    }

  if (!legacy_mode)
    {
      cogl_pipeline_set_color4ub (pipeline, Cr, Cg, Cb, Ca);

      cogl_framebuffer_set_depth_write_enabled (test_fb,
                                                rect_state->fb_write_enable);
      cogl_framebuffer_push_matrix (test_fb);
      cogl_framebuffer_translate (test_fb, 0, 0, rect_state->depth);
      cogl_framebuffer_draw_rectangle (test_fb,
                                       pipeline,
                                       x * QUAD_WIDTH,
                                       y * QUAD_WIDTH,
                                       x * QUAD_WIDTH + QUAD_WIDTH,
                                       y * QUAD_WIDTH + QUAD_WIDTH);
      cogl_framebuffer_pop_matrix (test_fb);
    }
  else
    {
      cogl_push_framebuffer (test_fb);
      cogl_push_matrix ();
      cogl_set_source_color4ub (Cr, Cg, Cb, Ca);
      cogl_translate (0, 0, rect_state->depth);
      cogl_rectangle (x * QUAD_WIDTH,
                      y * QUAD_WIDTH,
                      x * QUAD_WIDTH + QUAD_WIDTH,
                      y * QUAD_WIDTH + QUAD_WIDTH);
      cogl_pop_matrix ();
      cogl_pop_framebuffer ();
    }

  cogl_object_unref (pipeline);

  return TRUE;
}
static CoglPipeline *
create_1d_gaussian_blur_pipeline (RutContext *ctx, int n_taps)
{
  static GHashTable *pipeline_cache = NULL;
  CoglPipeline *pipeline;
  CoglSnippet *snippet;
  GString *shader;
  CoglDepthState depth_state;
  int i;

  /* initialize the pipeline cache. The shaders are only dependent on the
   * number of taps, not the sigma, so we cache the corresponding pipelines
   * in a hash table 'n_taps' => 'pipeline' */
  if (G_UNLIKELY (pipeline_cache == NULL))
    {
      pipeline_cache =
        g_hash_table_new_full (g_direct_hash,
                               g_direct_equal,
                               NULL, /* key destroy notify */
                               (GDestroyNotify) cogl_object_unref);
    }

  pipeline = g_hash_table_lookup (pipeline_cache, GINT_TO_POINTER (n_taps));
  if (pipeline)
    return cogl_object_ref (pipeline);

  shader = g_string_new (NULL);

  g_string_append_printf (shader,
                          "uniform vec2 pixel_step;\n"
                          "uniform float factors[%i];\n",
                          n_taps);

  snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP,
                              shader->str,
                              NULL /* post */);

  g_string_set_size (shader, 0);

  pipeline = cogl_pipeline_new (ctx->cogl_context);
  cogl_pipeline_set_layer_null_texture (pipeline,
                                        0, /* layer_num */
                                        COGL_TEXTURE_TYPE_2D);
  cogl_pipeline_set_layer_wrap_mode (pipeline,
                                     0, /* layer_num */
                                     COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
  cogl_pipeline_set_layer_filters (pipeline,
                                   0, /* layer_num */
                                   COGL_PIPELINE_FILTER_NEAREST,
                                   COGL_PIPELINE_FILTER_NEAREST);

  for (i = 0; i < n_taps; i++)
    {
      g_string_append (shader, "cogl_texel ");

      if (i == 0)
        g_string_append (shader, "=");
      else
        g_string_append (shader, "+=");

      g_string_append_printf (shader,
                              " texture2D (cogl_sampler, "
                              "cogl_tex_coord.st");
      if (i != (n_taps - 1) / 2)
        g_string_append_printf (shader,
                                " + pixel_step * %f",
                                (float) (i - ((n_taps - 1) / 2)));
      g_string_append_printf (shader,
                              ") * factors[%i];\n",
                              i);
    }

  cogl_snippet_set_replace (snippet, shader->str);

  g_string_free (shader, TRUE);

  cogl_pipeline_add_layer_snippet (pipeline, 0, snippet);

  cogl_object_unref (snippet);

  cogl_pipeline_set_blend (pipeline, "RGBA=ADD(SRC_COLOR, 0)", NULL);

  cogl_depth_state_init (&depth_state);
  cogl_depth_state_set_write_enabled (&depth_state, FALSE);
  cogl_depth_state_set_test_enabled (&depth_state, FALSE);
  cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL);

  g_hash_table_insert (pipeline_cache, GINT_TO_POINTER (n_taps), pipeline);

  return pipeline;
}
static CoglPipeline *
get_entity_color_pipeline (RigEngine *engine,
                           RutEntity *entity,
                           RutComponent *geometry,
                           CoglBool blended)
{
  CoglSnippet *snippet;
  CoglDepthState depth_state;
  RutMaterial *material;
  CoglTexture *texture = NULL;
  CoglTexture *normal_map = NULL;
  CoglTexture *alpha_mask = NULL;
  CoglPipeline *pipeline;
  CoglFramebuffer *shadow_fb;

  if (blended)
    pipeline = rut_entity_get_pipeline_cache (entity,
                                              CACHE_SLOT_COLOR_BLENDED);
  else
    pipeline = rut_entity_get_pipeline_cache (entity,
                                              CACHE_SLOT_COLOR_UNBLENDED);
  if (pipeline)
    {
      cogl_object_ref (pipeline);
      goto FOUND;
    }

  pipeline = cogl_pipeline_new (engine->ctx->cogl_context);

  material = rut_entity_get_component (entity, RUT_COMPONENT_TYPE_MATERIAL);
  if (material)
    {
      RutAsset *texture_asset = rut_material_get_texture_asset (material);
      RutAsset *normal_map_asset =
        rut_material_get_normal_map_asset (material);
      RutAsset *alpha_mask_asset =
        rut_material_get_alpha_mask_asset (material);

      if (texture_asset)
        texture = rut_asset_get_texture (texture_asset);
      if (texture)
        cogl_pipeline_set_layer_texture (pipeline, 1, texture);

      if (normal_map_asset)
        normal_map = rut_asset_get_texture (normal_map_asset);

      if (alpha_mask_asset)
        alpha_mask = rut_asset_get_texture (alpha_mask_asset);
    }

#if 0
  /* NB: Our texture colours aren't premultiplied */
  cogl_pipeline_set_blend (pipeline,
                           "RGB = ADD(SRC_COLOR*(SRC_COLOR[A]), DST_COLOR*(1-SRC_COLOR[A]))"
                           "A   = ADD(SRC_COLOR, DST_COLOR*(1-SRC_COLOR[A]))",
                           NULL);
#endif

#if 0
  if (rut_object_get_type (geometry) == &rut_shape_type)
    rut_geometry_component_update_pipeline (geometry, pipeline);

  pipeline = cogl_pipeline_new (rut_cogl_context);
#endif

  cogl_pipeline_set_color4f (pipeline, 0.8f, 0.8f, 0.8f, 1.f);

  /* enable depth testing */
  cogl_depth_state_init (&depth_state);
  cogl_depth_state_set_test_enabled (&depth_state, TRUE);

  if (blended)
    cogl_depth_state_set_write_enabled (&depth_state, FALSE);

  cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL);

  /* Vertex shader setup for lighting */
  cogl_pipeline_add_snippet (pipeline, engine->lighting_vertex_snippet);

  if (normal_map)
    cogl_pipeline_add_snippet (pipeline, engine->normal_map_vertex_snippet);

  if (rut_entity_get_receive_shadow (entity))
    cogl_pipeline_add_snippet (pipeline, engine->shadow_mapping_vertex_snippet);

  /* and fragment shader */

  /* XXX: ideally we wouldn't have to rely on conditionals + discards
   * in the fragment shader to differentiate blended and unblended
   * regions and instead we should let users mark out opaque regions
   * in geometry.
   */
  cogl_pipeline_add_snippet (pipeline,
                             blended ?
                             engine->blended_discard_snippet :
                             engine->unblended_discard_snippet);

  cogl_pipeline_add_snippet (pipeline, engine->unpremultiply_snippet);

  if (material)
    {
      if (alpha_mask)
        {
          /* We don't want this layer to be automatically modulated with the
           * previous layers so we set its combine mode to "REPLACE" so it
           * will be skipped past and we can sample its texture manually */
          cogl_pipeline_set_layer_combine (pipeline, 2, "RGBA=REPLACE(PREVIOUS)", NULL);
          cogl_pipeline_set_layer_texture (pipeline, 2, alpha_mask);

          cogl_pipeline_add_snippet (pipeline, engine->alpha_mask_snippet);
        }

      if (normal_map)
        {
          /* We don't want this layer to be automatically modulated with the
           * previous layers so we set its combine mode to "REPLACE" so it
           * will be skipped past and we can sample its texture manually */
          cogl_pipeline_set_layer_combine (pipeline, 5, "RGBA=REPLACE(PREVIOUS)", NULL);
          cogl_pipeline_set_layer_texture (pipeline, 5, normal_map);

          snippet = engine->normal_map_fragment_snippet;
        }
      else
        {
          snippet = engine->material_lighting_snippet;
        }
    }
  else
    {
      snippet = engine->simple_lighting_snippet;
    }

  cogl_pipeline_add_snippet (pipeline, snippet);

  if (rut_entity_get_receive_shadow (entity))
    {
      /* Hook the shadow map sampling */

      cogl_pipeline_set_layer_texture (pipeline, 7, engine->shadow_map);
      /* For debugging the shadow mapping... */
      //cogl_pipeline_set_layer_texture (pipeline, 7, engine->shadow_color);
      //cogl_pipeline_set_layer_texture (pipeline, 7, engine->gradient);

      /* We don't want this layer to be automatically modulated with the
       * previous layers so we set its combine mode to "REPLACE" so it
       * will be skipped past and we can sample its texture manually */
      cogl_pipeline_set_layer_combine (pipeline, 7, "RGBA=REPLACE(PREVIOUS)", NULL);

      /* Handle shadow mapping */
      cogl_pipeline_add_snippet (pipeline,
                                 engine->shadow_mapping_fragment_snippet);
    }

  cogl_pipeline_add_snippet (pipeline, engine->premultiply_snippet);

  if (rut_object_get_type (geometry) == &rut_shape_type)
    {
      CoglTexture *shape_texture;

      if (rut_shape_get_shaped (RUT_SHAPE (geometry)))
        {
          shape_texture =
            rut_shape_get_shape_texture (RUT_SHAPE (geometry));
          cogl_pipeline_set_layer_texture (pipeline, 0, shape_texture);
        }

      rut_shape_add_reshaped_callback (RUT_SHAPE (geometry),
                                       reshape_cb,
                                       NULL,
                                       NULL);
    }
  else if (rut_object_get_type (geometry) == &rut_diamond_type)
    rut_diamond_apply_mask (RUT_DIAMOND (geometry), pipeline);

  if (!blended)
    {
      cogl_pipeline_set_blend (pipeline, "RGBA = ADD (SRC_COLOR, 0)", NULL);
      rut_entity_set_pipeline_cache (entity,
                                     CACHE_SLOT_COLOR_UNBLENDED, pipeline);
    }
  else
    {
      rut_entity_set_pipeline_cache (entity,
                                     CACHE_SLOT_COLOR_BLENDED, pipeline);
    }

FOUND:

  /* FIXME: there's lots to optimize about this! */
  shadow_fb = COGL_FRAMEBUFFER (engine->shadow_fb);

  /* update uniforms in pipelines */
  {
    CoglMatrix light_shadow_matrix, light_projection;
    CoglMatrix model_transform;
    const float *light_matrix;
    int location;

    cogl_framebuffer_get_projection_matrix (shadow_fb, &light_projection);

    /* XXX: This is pretty bad that we are having to do this. It would
     * be nicer if cogl exposed matrix-stacks publicly so we could
     * maintain the entity model_matrix incrementally as we traverse
     * the scenegraph. */
    rut_graphable_get_transform (entity, &model_transform);

    get_light_modelviewprojection (&model_transform,
                                   engine->light,
                                   &light_projection,
                                   &light_shadow_matrix);

    light_matrix = cogl_matrix_get_array (&light_shadow_matrix);

    location = cogl_pipeline_get_uniform_location (pipeline,
                                                   "light_shadow_matrix");
    cogl_pipeline_set_uniform_matrix (pipeline,
                                      location,
                                      4, 1,
                                      FALSE,
                                      light_matrix);
  }

  return pipeline;
}
static CoglPipeline *
get_entity_mask_pipeline (RigEngine *engine,
                          RutEntity *entity,
                          RutComponent *geometry)
{
  CoglPipeline *pipeline;

  pipeline = rut_entity_get_pipeline_cache (entity, CACHE_SLOT_SHADOW);
  if (pipeline)
    return cogl_object_ref (pipeline);

  /* TODO: move into init() somewhere */
  if (G_UNLIKELY (!engine->dof_pipeline_template))
    {
      CoglPipeline *pipeline;
      CoglDepthState depth_state;
      CoglSnippet *snippet;

      pipeline = cogl_pipeline_new (engine->ctx->cogl_context);

      cogl_pipeline_set_color_mask (pipeline, COGL_COLOR_MASK_ALPHA);

      cogl_pipeline_set_blend (pipeline, "RGBA=ADD(SRC_COLOR, 0)", NULL);

      cogl_depth_state_init (&depth_state);
      cogl_depth_state_set_test_enabled (&depth_state, TRUE);
      cogl_pipeline_set_depth_state (pipeline, &depth_state, NULL);

      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,

                                  /* definitions */
                                  "uniform float dof_focal_distance;\n"
                                  "uniform float dof_depth_of_field;\n"

                                  "varying float dof_blur;\n",
                                  //"varying vec4 world_pos;\n",

                                  /* compute the amount of bluriness we want */
                                  "vec4 world_pos = cogl_modelview_matrix * cogl_position_in;\n"
                                  //"world_pos = cogl_modelview_matrix * cogl_position_in;\n"
                                  "dof_blur = 1.0 - clamp (abs (world_pos.z - dof_focal_distance) /\n"
                                  "                  dof_depth_of_field, 0.0, 1.0);\n"
      );

      cogl_pipeline_add_snippet (pipeline, snippet);
      cogl_object_unref (snippet);

      /* This was used to debug the focal distance and bluriness amount in the DoF
       * effect: */
#if 0
      cogl_pipeline_set_color_mask (pipeline, COGL_COLOR_MASK_ALL);
      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
                                  "varying vec4 world_pos;\n"
                                  "varying float dof_blur;",

                                  "cogl_color_out = vec4(dof_blur,0,0,1);\n"
                                  //"cogl_color_out = vec4(1.0, 0.0, 0.0, 1.0);\n"
                                  //"if (world_pos.z < -30.0) cogl_color_out = vec4(0,1,0,1);\n"
                                  //"if (abs (world_pos.z + 30.f) < 0.1) cogl_color_out = vec4(0,1,0,1);\n"
                                  "cogl_color_out.a = dof_blur;\n"
                                  //"cogl_color_out.a = 1.0;\n"
      );

      cogl_pipeline_add_snippet (pipeline, snippet);
      cogl_object_unref (snippet);
#endif

      engine->dof_pipeline_template = pipeline;
    }

  /* TODO: move into init() somewhere */
  if (G_UNLIKELY (!engine->dof_diamond_pipeline))
    {
      CoglPipeline *dof_diamond_pipeline =
        cogl_pipeline_copy (engine->dof_pipeline_template);
      CoglSnippet *snippet;

      cogl_pipeline_set_layer_texture (dof_diamond_pipeline,
                                       0,
                                       engine->ctx->circle_texture);

      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
                                  /* declarations */
                                  "varying float dof_blur;",

                                  /* post */
                                  "if (cogl_color_out.a <= 0.0)\n"
                                  "  discard;\n"
                                  "\n"
                                  "cogl_color_out.a = dof_blur;\n");

      cogl_pipeline_add_snippet (dof_diamond_pipeline, snippet);
      cogl_object_unref (snippet);

      engine->dof_diamond_pipeline = dof_diamond_pipeline;
    }

  /* TODO: move into init() somewhere */
  if (G_UNLIKELY (!engine->dof_unshaped_pipeline))
    {
      CoglPipeline *dof_unshaped_pipeline =
        cogl_pipeline_copy (engine->dof_pipeline_template);
      CoglSnippet *snippet;

      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
                                  /* declarations */
                                  "varying float dof_blur;",

                                  /* post */
                                  "if (cogl_color_out.a < 0.25)\n"
                                  "  discard;\n"
                                  "\n"
                                  "cogl_color_out.a = dof_blur;\n");

      cogl_pipeline_add_snippet (dof_unshaped_pipeline, snippet);
      cogl_object_unref (snippet);

      engine->dof_unshaped_pipeline = dof_unshaped_pipeline;
    }

  /* TODO: move into init() somewhere */
  if (G_UNLIKELY (!engine->dof_pipeline))
    {
      CoglPipeline *dof_pipeline =
        cogl_pipeline_copy (engine->dof_pipeline_template);
      CoglSnippet *snippet;

      /* store the bluriness in the alpha channel */
      snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
                                  "varying float dof_blur;",

                                  "cogl_color_out.a = dof_blur;\n"
      );
      cogl_pipeline_add_snippet (dof_pipeline, snippet);
      cogl_object_unref (snippet);

      engine->dof_pipeline = dof_pipeline;
    }

  if (rut_object_get_type (geometry) == &rut_diamond_type)
    {
      pipeline = cogl_object_ref (engine->dof_diamond_pipeline);
    }
  else if (rut_object_get_type (geometry) == &rut_shape_type)
    {
      RutMaterial *material =
        rut_entity_get_component (entity, RUT_COMPONENT_TYPE_MATERIAL);

      pipeline = cogl_pipeline_copy (engine->dof_unshaped_pipeline);

      if (rut_shape_get_shaped (RUT_SHAPE (geometry)))
        {
          CoglTexture *shape_texture =
            rut_shape_get_shape_texture (RUT_SHAPE (geometry));

          cogl_pipeline_set_layer_texture (pipeline, 0, shape_texture);
        }

      if (material)
        {
          RutAsset *texture_asset = rut_material_get_texture_asset (material);
          RutAsset *alpha_mask_asset =
            rut_material_get_alpha_mask_asset (material);

          if (texture_asset)
            cogl_pipeline_set_layer_texture (pipeline, 1,
                                             rut_asset_get_texture (texture_asset));

          if (alpha_mask_asset)
            {
              /* We don't want this layer to be automatically modulated with the
               * previous layers so we set its combine mode to "REPLACE" so it
               * will be skipped past and we can sample its texture manually */
              cogl_pipeline_set_layer_combine (pipeline, 2, "RGBA=REPLACE(PREVIOUS)", NULL);
              cogl_pipeline_set_layer_texture (pipeline, 2,
                                               rut_asset_get_texture (alpha_mask_asset));

              cogl_pipeline_add_snippet (pipeline, engine->alpha_mask_snippet);
            }
        }
    }
  else
    pipeline = cogl_object_ref (engine->dof_pipeline);

  rut_entity_set_pipeline_cache (entity, CACHE_SLOT_SHADOW, pipeline);

  return pipeline;
}